mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-20 23:08:31 +08:00
GP-3013 Refactor of Relocation API (created V6 DB adapter) to include
status and stored length when original FileBytes are used.
This commit is contained in:
+73
-22
@@ -25,6 +25,7 @@ import ghidra.docking.settings.Settings;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.util.NumericUtilities;
|
||||
@@ -51,15 +52,19 @@ class RelocationTableModel extends AddressBasedTableModel<RelocationRowObject> {
|
||||
};
|
||||
|
||||
static final int ADDRESS_COL = 0;
|
||||
static final int TYPE_COL = 1;
|
||||
static final int VALUE_COL = 2;
|
||||
static final int BYTES_COL = 3;
|
||||
static final int NAME_COL = 4;
|
||||
static final int STATUS_COL = 1;
|
||||
static final int TYPE_COL = 2;
|
||||
static final int VALUE_COL = 3;
|
||||
static final int ORIGINAL_BYTES_COL = 4;
|
||||
static final int MODIFIED_BYTES_COL = 5;
|
||||
static final int NAME_COL = 6;
|
||||
|
||||
static final String RELOCATION_ADDRESS = "Address";
|
||||
static final String RELOCATION_STATUS = "Status";
|
||||
static final String RELOCATION_TYPE = "Type";
|
||||
static final String RELOCATION_VALUE = "Values";
|
||||
static final String RELOCATION_BYTES = "Original Bytes";
|
||||
static final String RELOCATION_ORIGINAL_BYTES = "Original Bytes";
|
||||
static final String RELOCATION_CURRENT_BYTES = "Current Bytes";
|
||||
static final String RELOCATION_NAME = "Name";
|
||||
|
||||
public RelocationTableModel(ServiceProvider serviceProvider, Program program,
|
||||
@@ -73,9 +78,11 @@ class RelocationTableModel extends AddressBasedTableModel<RelocationRowObject> {
|
||||
|
||||
descriptor.addVisibleColumn(
|
||||
DiscoverableTableUtils.adaptColumForModel(this, new AddressTableColumn()), 1, true);
|
||||
descriptor.addVisibleColumn(new RelocationStatusColumn());
|
||||
descriptor.addVisibleColumn(new RelocationTypeColumn());
|
||||
descriptor.addVisibleColumn(new RelocationValueColumn());
|
||||
descriptor.addVisibleColumn(new RelocationBytesColumn());
|
||||
descriptor.addVisibleColumn(new RelocationOriginalBytesColumn());
|
||||
descriptor.addHiddenColumn(new RelocationCurrentBytesColumn());
|
||||
descriptor.addVisibleColumn(new RelocationNameColumn());
|
||||
|
||||
return descriptor;
|
||||
@@ -118,6 +125,24 @@ class RelocationTableModel extends AddressBasedTableModel<RelocationRowObject> {
|
||||
return rowObject.relocation.getAddress();
|
||||
}
|
||||
|
||||
private static String packBytes(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (long b : bytes) {
|
||||
if (buf.length() != 0) {
|
||||
buf.append(' ');
|
||||
}
|
||||
String byteStr = Long.toHexString(b & 0xff);
|
||||
if (byteStr.length() == 1) {
|
||||
buf.append('0');
|
||||
}
|
||||
buf.append(byteStr);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
@@ -137,6 +162,22 @@ class RelocationTableModel extends AddressBasedTableModel<RelocationRowObject> {
|
||||
}
|
||||
}
|
||||
|
||||
private static class RelocationStatusColumn extends
|
||||
AbstractProgramBasedDynamicTableColumn<RelocationRowObject, String> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return RELOCATION_STATUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(RelocationRowObject rowObject, Settings settings, Program program,
|
||||
ServiceProvider serviceProvider) throws IllegalArgumentException {
|
||||
return rowObject.relocation.getStatus().name();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class RelocationTypeColumn extends
|
||||
AbstractProgramBasedDynamicTableColumn<RelocationRowObject, String> {
|
||||
|
||||
@@ -182,12 +223,12 @@ class RelocationTableModel extends AddressBasedTableModel<RelocationRowObject> {
|
||||
}
|
||||
}
|
||||
|
||||
private static class RelocationBytesColumn extends
|
||||
private static class RelocationOriginalBytesColumn extends
|
||||
AbstractProgramBasedDynamicTableColumn<RelocationRowObject, String> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return RELOCATION_BYTES;
|
||||
return RELOCATION_ORIGINAL_BYTES;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -195,23 +236,33 @@ class RelocationTableModel extends AddressBasedTableModel<RelocationRowObject> {
|
||||
ServiceProvider serviceProvider) throws IllegalArgumentException {
|
||||
return packBytes(rowObject.relocation.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
private String packBytes(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return "";
|
||||
private static class RelocationCurrentBytesColumn extends
|
||||
AbstractProgramBasedDynamicTableColumn<RelocationRowObject, String> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return RELOCATION_CURRENT_BYTES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(RelocationRowObject rowObject, Settings settings, Program program,
|
||||
ServiceProvider serviceProvider) throws IllegalArgumentException {
|
||||
|
||||
Relocation relocation = rowObject.relocation;
|
||||
byte[] originalBytes = rowObject.relocation.getBytes();
|
||||
if (originalBytes == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (long b : bytes) {
|
||||
if (buf.length() != 0) {
|
||||
buf.append(' ');
|
||||
}
|
||||
String byteStr = Long.toHexString(b & 0xff);
|
||||
if (byteStr.length() == 1) {
|
||||
buf.append('0');
|
||||
}
|
||||
buf.append(byteStr);
|
||||
byte[] bytes = new byte[originalBytes.length];
|
||||
try {
|
||||
program.getMemory().getBytes(relocation.getAddress(), bytes);
|
||||
}
|
||||
return buf.toString();
|
||||
catch (MemoryAccessException e) {
|
||||
return null;
|
||||
}
|
||||
return packBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-4
@@ -20,8 +20,9 @@ import ghidra.app.util.bin.format.coff.CoffFileHeader;
|
||||
import ghidra.app.util.bin.format.coff.CoffRelocation;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
/**
|
||||
* An abstract class used to perform COFF relocations. Classes should extend this class to
|
||||
@@ -44,12 +45,15 @@ public interface CoffRelocationHandler extends ExtensionPoint {
|
||||
* @param address The address at which to perform the relocation.
|
||||
* @param relocation The relocation information to use to perform the relocation.
|
||||
* @param relocationContext relocation context data
|
||||
* @return applied relocation result (conveys status and applied byte-length)
|
||||
* @throws MemoryAccessException If there is a problem accessing memory during the relocation.
|
||||
* @throws NotFoundException If this handler didn't find a way to perform the relocation.
|
||||
* @throws RelocationException if supported relocation encountered an error during processing.
|
||||
* This exception should be thrown in place of returning {@link RelocationResult#FAILURE} or
|
||||
* a status of {@link Status#FAILURE} which will facilitate a failure reason via
|
||||
* {@link RelocationException#getMessage()}.
|
||||
*/
|
||||
public void relocate(Address address, CoffRelocation relocation,
|
||||
public RelocationResult relocate(Address address, CoffRelocation relocation,
|
||||
CoffRelocationContext relocationContext)
|
||||
throws MemoryAccessException, NotFoundException, RelocationException;
|
||||
throws MemoryAccessException, RelocationException;
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -379,11 +379,11 @@ public class ElfDefaultGotPltMarkup {
|
||||
// TODO: record artificial relative relocation for reversion/export concerns
|
||||
entry1Value += imageBaseAdj; // adjust first entry value
|
||||
if (elf.is64Bit()) {
|
||||
elfLoadHelper.addFakeRelocTableEntry(gotStart, 8);
|
||||
elfLoadHelper.addArtificialRelocTableEntry(gotStart, 8);
|
||||
memory.setLong(gotStart, entry1Value);
|
||||
}
|
||||
else {
|
||||
elfLoadHelper.addFakeRelocTableEntry(gotStart, 4);
|
||||
elfLoadHelper.addArtificialRelocTableEntry(gotStart, 4);
|
||||
memory.setInt(gotStart, (int) entry1Value);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -22,6 +22,7 @@ import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
@@ -213,10 +214,10 @@ public interface ElfLoadHelper {
|
||||
throws MemoryAccessException;
|
||||
|
||||
/**
|
||||
* Add a fake relocation table entry if none previously existed for the specified address.
|
||||
* Add an artificial relocation table entry if none previously existed for the specified address.
|
||||
* This is intended to record original file bytes when forced modifications have been
|
||||
* performed during the ELF import processing. A relocation type of 0 will be specified for
|
||||
* fake entry.
|
||||
* performed during the ELF import processing. A relocation type of 0 and a status of
|
||||
* {@link Status#APPLIED_OTHER} will be applied to the relocation entry.
|
||||
* NOTE: The number of recorded original FileBytes currently ignores the specified length.
|
||||
* However, the length is still used to verify that that the intended modification region
|
||||
* dose not intersect another relocation.
|
||||
@@ -225,6 +226,6 @@ public interface ElfLoadHelper {
|
||||
* @return true if recorded successfully, or false if conflict with existing relocation
|
||||
* entry and memory addressing error occurs
|
||||
*/
|
||||
public boolean addFakeRelocTableEntry(Address address, int length);
|
||||
public boolean addArtificialRelocTableEntry(Address address, int length);
|
||||
|
||||
}
|
||||
|
||||
+9
-5
@@ -26,6 +26,7 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.util.exception.*;
|
||||
|
||||
/**
|
||||
@@ -85,12 +86,14 @@ public class ElfRelocationContext {
|
||||
* All relocation entries must be processed in the order they appear within the table.
|
||||
* @param relocation relocation to be processed
|
||||
* @param relocationAddress relocation address where it should be applied
|
||||
* @return applied relocation result
|
||||
*/
|
||||
public final void processRelocation(ElfRelocation relocation, Address relocationAddress) {
|
||||
public final RelocationResult processRelocation(ElfRelocation relocation,
|
||||
Address relocationAddress) {
|
||||
|
||||
if (handler == null) {
|
||||
handleNoHandlerError(relocation, relocationAddress);
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
@@ -98,21 +101,22 @@ public class ElfRelocationContext {
|
||||
if (sym == null) {
|
||||
ElfRelocationHandler.markAsUnhandled(program, relocationAddress, relocation.getType(),
|
||||
symbolIndex, "index " + symbolIndex, getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
if (sym.isTLS()) {
|
||||
handleUnsupportedTLSRelocation(relocation, relocationAddress, sym);
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
handler.relocate(this, relocation, relocationAddress);
|
||||
return handler.relocate(this, relocation, relocationAddress);
|
||||
}
|
||||
catch (MemoryAccessException | NotFoundException e) {
|
||||
loadHelper.log(e);
|
||||
ElfRelocationHandler.markAsUnhandled(program, relocationAddress, relocation.getType(),
|
||||
symbolIndex, sym.getNameAsString(), getLog());
|
||||
}
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-1
@@ -27,6 +27,7 @@ import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
||||
import ghidra.program.model.data.PointerTypedef;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
@@ -74,10 +75,11 @@ abstract public class ElfRelocationHandler implements ExtensionPoint {
|
||||
* @param elfRelocationContext relocation context
|
||||
* @param relocation ELF relocation
|
||||
* @param relocationAddress relocation target address (fixup location)
|
||||
* @return applied relocation result (conveys status and applied byte-length)
|
||||
* @throws MemoryAccessException memory access failure
|
||||
* @throws NotFoundException required relocation data not found
|
||||
*/
|
||||
abstract public void relocate(ElfRelocationContext elfRelocationContext,
|
||||
abstract public RelocationResult relocate(ElfRelocationContext elfRelocationContext,
|
||||
ElfRelocation relocation, Address relocationAddress)
|
||||
throws MemoryAccessException, NotFoundException;
|
||||
|
||||
|
||||
+19
-27
@@ -25,8 +25,10 @@ import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.DataConverter;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public abstract class AbstractClassicProcessor {
|
||||
@@ -70,12 +72,9 @@ public abstract class AbstractClassicProcessor {
|
||||
|
||||
long offset = symbol.getAddress().getOffset();
|
||||
|
||||
boolean handled = false;
|
||||
|
||||
int fileType = header.getFileType();
|
||||
|
||||
byte originalBytes[] = new byte[0];
|
||||
|
||||
int byteLength = 0;
|
||||
switch (fileType) {
|
||||
|
||||
case MachHeaderFileTypes.MH_EXECUTE:
|
||||
@@ -85,13 +84,8 @@ public abstract class AbstractClassicProcessor {
|
||||
|
||||
byte[] bytes = (program.getDefaultPointerSize() == 8) ? converter.getBytes(offset)
|
||||
: converter.getBytes((int) offset);
|
||||
|
||||
originalBytes = new byte[bytes.length];
|
||||
memory.getBytes(address, originalBytes);
|
||||
memory.setBytes(address, bytes);
|
||||
|
||||
handled = true;
|
||||
|
||||
byteLength = bytes.length;
|
||||
break;
|
||||
}
|
||||
case MachHeaderFileTypes.MH_KEXT_BUNDLE: {
|
||||
@@ -108,20 +102,15 @@ public abstract class AbstractClassicProcessor {
|
||||
|
||||
long difference = offset - addressValue - 4;
|
||||
byte[] bytes = converter.getBytes((int) difference);
|
||||
originalBytes = new byte[bytes.length];
|
||||
memory.getBytes(address, originalBytes);
|
||||
memory.setBytes(address, bytes);
|
||||
handled = true;
|
||||
byteLength = bytes.length;
|
||||
}
|
||||
}
|
||||
else {
|
||||
byte[] bytes = (program.getDefaultPointerSize() == 8)
|
||||
? converter.getBytes(offset) : converter.getBytes((int) offset);
|
||||
|
||||
originalBytes = new byte[bytes.length];
|
||||
memory.getBytes(address, originalBytes);
|
||||
memory.setBytes(address, bytes);
|
||||
handled = true;
|
||||
byteLength = bytes.length;
|
||||
}
|
||||
}
|
||||
else if (header.getCpuType() == CpuTypes.CPU_TYPE_POWERPC) {//TODO powerpc kext files
|
||||
@@ -140,11 +129,8 @@ public abstract class AbstractClassicProcessor {
|
||||
case MachHeaderFileTypes.MH_OBJECT: {
|
||||
byte[] bytes = (program.getDefaultPointerSize() == 8) ? converter.getBytes(offset)
|
||||
: converter.getBytes((int) offset);
|
||||
|
||||
originalBytes = new byte[bytes.length];
|
||||
memory.getBytes(address, originalBytes);
|
||||
memory.setBytes(address, bytes);
|
||||
handled = true;
|
||||
byteLength = bytes.length;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -152,15 +138,21 @@ public abstract class AbstractClassicProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
// put an entry in the relocation table, handled or not
|
||||
String symbolName = symbol.getName();
|
||||
program.getRelocationTable().add(address, fileType, new long[0], originalBytes, symbolName);
|
||||
|
||||
if (!handled) {
|
||||
Status status;
|
||||
if (byteLength <= 0) {
|
||||
program.getBookmarkManager().setBookmark(address, BookmarkType.ERROR,
|
||||
"Unhandled Classic Binding", "Unable to fixup classic binding. " +
|
||||
"This instruction will contain an invalid destination / fixup.");
|
||||
status = Status.UNSUPPORTED;
|
||||
}
|
||||
else {
|
||||
status = Status.APPLIED;
|
||||
}
|
||||
|
||||
// put an entry in the relocation table, handled or not
|
||||
String symbolName = symbol.getName();
|
||||
program.getRelocationTable()
|
||||
.add(address, status, fileType, null, byteLength, symbolName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-4
@@ -138,8 +138,6 @@ public class DyldCacheSlideInfo1 extends DyldCacheSlideInfoCommon {
|
||||
|
||||
List<Address> unchainedLocList = new ArrayList<>(1024);
|
||||
|
||||
byte origBytes[] = new byte[8];
|
||||
|
||||
monitor.setMessage("Fixing V1 chained data page pointers...");
|
||||
|
||||
monitor.setMaximum(entries_count);
|
||||
@@ -174,8 +172,7 @@ public class DyldCacheSlideInfo1 extends DyldCacheSlideInfoCommon {
|
||||
|
||||
// not actually changing bytes, so not really a relocation, but a relocate-able place
|
||||
if (addRelocations) {
|
||||
addRelocationTableEntry(program, addr, 0x1000, value, origBytes,
|
||||
null);
|
||||
addRelocationTableEntry(program, addr, 0x1000, value, 8, null);
|
||||
}
|
||||
//memory.setLong(addr, value);
|
||||
|
||||
|
||||
+1
-3
@@ -212,8 +212,6 @@ public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon {
|
||||
Memory memory = program.getMemory();
|
||||
List<Address> unchainedLocList = new ArrayList<>(1024);
|
||||
|
||||
byte origBytes[] = new byte[8];
|
||||
|
||||
long valueMask = 0xffffffffffffffffL >>> (64 - deltaShift);
|
||||
|
||||
long delta = -1;
|
||||
@@ -230,7 +228,7 @@ public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon {
|
||||
// chainValue += slideAmount - if we were sliding
|
||||
}
|
||||
if (addRelocations) {
|
||||
addRelocationTableEntry(program, chainLoc, 2, chainValue, origBytes, null);
|
||||
addRelocationTableEntry(program, chainLoc, 2, chainValue, 8, null);
|
||||
}
|
||||
|
||||
memory.setLong(chainLoc, chainValue);
|
||||
|
||||
+1
-3
@@ -172,8 +172,6 @@ public class DyldCacheSlideInfo3 extends DyldCacheSlideInfoCommon {
|
||||
|
||||
List<Address> unchainedLocList = new ArrayList<>(1024);
|
||||
|
||||
byte origBytes[] = new byte[8];
|
||||
|
||||
long delta = -1;
|
||||
while (delta != 0) {
|
||||
monitor.checkCanceled();
|
||||
@@ -201,7 +199,7 @@ public class DyldCacheSlideInfo3 extends DyldCacheSlideInfoCommon {
|
||||
|
||||
if (addRelocation) {
|
||||
addRelocationTableEntry(program, chainLoc, 3 * (isAuthenticated ? -1 : 1),
|
||||
chainValue, origBytes, null);
|
||||
chainValue, 8, null);
|
||||
}
|
||||
memory.setLong(chainLoc, chainValue);
|
||||
|
||||
|
||||
+1
-3
@@ -225,8 +225,6 @@ public class DyldCacheSlideInfo4 extends DyldCacheSlideInfoCommon {
|
||||
|
||||
List<Address> unchainedLocList = new ArrayList<Address>(1024);
|
||||
|
||||
byte origBytes[] = new byte[4];
|
||||
|
||||
int valueMask = 0xffffffff >>> (32 - deltaShift);
|
||||
|
||||
long delta = -1;
|
||||
@@ -250,7 +248,7 @@ public class DyldCacheSlideInfo4 extends DyldCacheSlideInfoCommon {
|
||||
}
|
||||
|
||||
if (addRelocations) {
|
||||
addRelocationTableEntry(program, chainLoc, 4, chainValue, origBytes, null);
|
||||
addRelocationTableEntry(program, chainLoc, 4, chainValue, 4, null);
|
||||
}
|
||||
|
||||
memory.setInt(chainLoc, chainValue);
|
||||
|
||||
+4
-3
@@ -26,6 +26,7 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
@@ -129,11 +130,11 @@ public abstract class DyldCacheSlideInfoCommon implements StructConverter {
|
||||
throws MemoryAccessException, CancelledException;
|
||||
|
||||
protected void addRelocationTableEntry(Program program, Address chainLoc, int type,
|
||||
long chainValue, byte[] origBytes, String name) throws MemoryAccessException {
|
||||
long chainValue, int appliedByteLength, String name) {
|
||||
// Add entry to relocation table for the pointer fixup
|
||||
program.getMemory().getBytes(chainLoc, origBytes);
|
||||
program.getRelocationTable()
|
||||
.add(chainLoc, type, new long[] { chainValue }, origBytes, name);
|
||||
.add(chainLoc, Status.APPLIED, type, new long[] { chainValue }, appliedByteLength,
|
||||
name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-2
@@ -18,6 +18,8 @@ package ghidra.app.util.bin.format.macho.dyld;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
|
||||
/**
|
||||
* @see <a href="https://opensource.apple.com/source/dyld/dyld-852.2/include/mach-o/fixup-chains.h.auto.html">mach-o/fixup-chains.h</a>
|
||||
@@ -112,8 +114,10 @@ public class DyldChainedPtr {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setChainValue(Memory memory, Address chainLoc, DyldChainType ptrFormat,
|
||||
public static RelocationResult setChainValue(Memory memory, Address chainLoc,
|
||||
DyldChainType ptrFormat,
|
||||
long value) throws MemoryAccessException {
|
||||
int byteLength;
|
||||
switch (ptrFormat) {
|
||||
case DYLD_CHAINED_PTR_ARM64E:
|
||||
case DYLD_CHAINED_PTR_ARM64E_USERLAND:
|
||||
@@ -125,16 +129,20 @@ public class DyldChainedPtr {
|
||||
case DYLD_CHAINED_PTR_ARM64E_FIRMWARE:
|
||||
case DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE:
|
||||
memory.setLong(chainLoc, value);
|
||||
byteLength = 8;
|
||||
break;
|
||||
|
||||
case DYLD_CHAINED_PTR_32:
|
||||
case DYLD_CHAINED_PTR_32_CACHE:
|
||||
case DYLD_CHAINED_PTR_32_FIRMWARE:
|
||||
memory.setInt(chainLoc, (int) (value & 0xFFFFFFFFL));
|
||||
byteLength = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED_OTHER, byteLength);
|
||||
}
|
||||
|
||||
public static long getChainValue(Memory memory, Address chainLoc, DyldChainType ptrFormat)
|
||||
|
||||
+7
-7
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.macho.relocation;
|
||||
|
||||
import ghidra.app.util.bin.format.RelocationException;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.app.util.bin.format.macho.commands.NList;
|
||||
import ghidra.app.util.bin.format.macho.commands.SymbolTableCommand;
|
||||
@@ -25,7 +26,6 @@ import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.util.NumericUtilities;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
/**
|
||||
* A representation of a single Mach-O relocation that the {@link MachoRelocationHandler} will use
|
||||
@@ -144,9 +144,9 @@ public class MachoRelocation {
|
||||
* Gets the {@link Address} of the relocation target
|
||||
*
|
||||
* @return The {@link Address} of the relocation target
|
||||
* @throws NotFoundException If the {@link Address} of the relocation target could not be found
|
||||
* @throws RelocationException If the {@link Address} of the relocation target could not be found
|
||||
*/
|
||||
public Address getTargetAddress() throws NotFoundException {
|
||||
public Address getTargetAddress() throws RelocationException {
|
||||
if (targetSymbol != null) {
|
||||
return targetSymbol.getAddress();
|
||||
}
|
||||
@@ -156,17 +156,17 @@ public class MachoRelocation {
|
||||
if (targetPointer != null) {
|
||||
return targetPointer;
|
||||
}
|
||||
throw new NotFoundException("Relocation target not found");
|
||||
throw new RelocationException("Relocation target not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Address} of the extra relocation target
|
||||
*
|
||||
* @return The {@link Address} of the extra relocation target
|
||||
* @throws NotFoundException If the {@link Address} of the extra relocation target could not be
|
||||
* @throws RelocationException If the {@link Address} of the extra relocation target could not be
|
||||
* found (of if there wasn't an extra relocation target).
|
||||
*/
|
||||
public Address getTargetAddressExtra() throws NotFoundException {
|
||||
public Address getTargetAddressExtra() throws RelocationException {
|
||||
if (targetSymbolExtra != null) {
|
||||
return targetSymbolExtra.getAddress();
|
||||
}
|
||||
@@ -176,7 +176,7 @@ public class MachoRelocation {
|
||||
if (targetPointerExtra != null) {
|
||||
return targetPointerExtra;
|
||||
}
|
||||
throw new NotFoundException("Extra relocation target not found");
|
||||
throw new RelocationException("Extra relocation target not found");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
-18
@@ -15,13 +15,15 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.macho.relocation;
|
||||
|
||||
import ghidra.app.util.bin.format.RelocationException;
|
||||
import ghidra.app.util.bin.format.macho.MachHeader;
|
||||
import ghidra.app.util.bin.format.macho.RelocationInfo;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
/**
|
||||
* An abstract class used to perform Mach-O relocations. Classes should extend this class to
|
||||
@@ -51,13 +53,17 @@ abstract public class MachoRelocationHandler implements ExtensionPoint {
|
||||
|
||||
/**
|
||||
* Performs a relocation
|
||||
|
||||
|
||||
* @param relocation The relocation to perform
|
||||
* @return applied relocation result
|
||||
* @throws MemoryAccessException If there is a problem accessing memory during the relocation
|
||||
* @throws NotFoundException If this handler didn't find a way to perform the relocation
|
||||
* @throws RelocationException if supported relocation encountered an error during processing.
|
||||
* This exception should be thrown in place of returning {@link RelocationResult#FAILURE} or
|
||||
* a status of {@link Status#FAILURE} which will facilitate a failure reason via
|
||||
* {@link RelocationException#getMessage()}.
|
||||
*/
|
||||
abstract public void relocate(MachoRelocation relocation)
|
||||
throws MemoryAccessException, NotFoundException;
|
||||
abstract public RelocationResult relocate(MachoRelocation relocation)
|
||||
throws MemoryAccessException, RelocationException;
|
||||
|
||||
/**
|
||||
* Reads bytes at the given address. The size of the read is determined by the length of the
|
||||
@@ -90,23 +96,25 @@ abstract public class MachoRelocationHandler implements ExtensionPoint {
|
||||
*
|
||||
* @param relocation The relocation to write
|
||||
* @param value The value to write
|
||||
* @return number of bytes written
|
||||
* @throws MemoryAccessException If there is a problem accessing memory during the write
|
||||
*/
|
||||
public static void write(MachoRelocation relocation, long value) throws MemoryAccessException {
|
||||
public static int write(MachoRelocation relocation, long value) throws MemoryAccessException {
|
||||
Memory mem = relocation.getProgram().getMemory();
|
||||
int len = relocation.getRelocationInfo().getLength();
|
||||
Address addr = relocation.getRelocationAddress();
|
||||
if (len == 3) {
|
||||
mem.setLong(addr, value);
|
||||
}
|
||||
else if (len == 2) {
|
||||
mem.setInt(addr, (int) value);
|
||||
}
|
||||
else if (len == 1) {
|
||||
mem.setShort(addr, (short) value);
|
||||
}
|
||||
else {
|
||||
mem.setByte(addr, (byte) value);
|
||||
switch (relocation.getRelocationInfo().getLength()) {
|
||||
case 3:
|
||||
mem.setLong(addr, value);
|
||||
return 8;
|
||||
case 2:
|
||||
mem.setInt(addr, (int) value);
|
||||
return 4;
|
||||
case 1:
|
||||
mem.setShort(addr, (short) value);
|
||||
return 2;
|
||||
default:
|
||||
mem.setByte(addr, (byte) value);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-9
@@ -20,6 +20,7 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
|
||||
/**
|
||||
* This class maintains the running state while
|
||||
@@ -200,23 +201,21 @@ public class RelocationState {
|
||||
if (block == null || !block.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
int value = memory.getInt(address);
|
||||
|
||||
byte[] bytes = new byte[4];
|
||||
memory.getBytes(address, bytes);
|
||||
long[] values = new long[] { addend };
|
||||
|
||||
// TODO does PEF have symbol names?
|
||||
String symbolName = null;
|
||||
program.getRelocationTable().add(address, -1, values, bytes, symbolName);
|
||||
|
||||
value += addend;
|
||||
memory.setInt(address, value);
|
||||
success = true;
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
log.appendMsg("Unable to perform change memory at " + address);
|
||||
}
|
||||
|
||||
// TODO does PEF have symbol names?
|
||||
Status status = success ? Status.APPLIED : Status.FAILURE;
|
||||
program.getRelocationTable().add(address, status, -1, new long[] { addend }, 4, null);
|
||||
}
|
||||
|
||||
private MemoryBlock getBlockContaining(Address address) {
|
||||
|
||||
@@ -35,10 +35,13 @@ import ghidra.program.model.data.Undefined;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class CoffLoader extends AbstractLibrarySupportLoader {
|
||||
@@ -666,6 +669,9 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
||||
sectionStartAddr.add(relocation.getAddress() - section.getVirtualAddress());
|
||||
short relocationType = relocation.getType();
|
||||
|
||||
Status status = Status.FAILURE;
|
||||
int byteLength = 0;
|
||||
|
||||
if (handler == null) {
|
||||
++failureCount;
|
||||
handleRelocationError(program, address, relocationType,
|
||||
@@ -677,6 +683,7 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
||||
// skip relocation if previous failed relocation was at the same address
|
||||
// since it is likely dependent on the previous failed relocation result
|
||||
++failureCount;
|
||||
status = Status.SKIPPED;
|
||||
|
||||
String logMessage =
|
||||
String.format("Skipped dependent COFF Relocation type 0x%x at %s",
|
||||
@@ -684,20 +691,24 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
||||
Msg.error(this, program.getName() + ": " + logMessage);
|
||||
}
|
||||
else {
|
||||
handler.relocate(address, relocation, relocationContext);
|
||||
RelocationResult result =
|
||||
handler.relocate(address, relocation, relocationContext);
|
||||
status = result.status();
|
||||
byteLength = result.byteLength();
|
||||
|
||||
if (status == Status.UNSUPPORTED) {
|
||||
++failureCount;
|
||||
failedAddr = address;
|
||||
handleRelocationError(program, address, relocationType,
|
||||
"Unsupported COFF relocation type", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
++failureCount;
|
||||
failedAddr = address;
|
||||
handleRelocationError(program, address, relocationType,
|
||||
"Error accessing memory", null);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
++failureCount;
|
||||
failedAddr = address;
|
||||
handleRelocationError(program, address, relocationType,
|
||||
"Unsupported COFF relocation type", null);
|
||||
"error accessing memory", null);
|
||||
}
|
||||
catch (RelocationException e) {
|
||||
++failureCount;
|
||||
@@ -705,7 +716,7 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
||||
handleRelocationError(program, address, relocationType, e.getMessage(),
|
||||
null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception e) { // handle unexpected exceptions
|
||||
++failureCount;
|
||||
failedAddr = address;
|
||||
String msg = e.getMessage();
|
||||
@@ -721,13 +732,9 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
||||
Symbol symbol =
|
||||
symbolsMap.get(header.getSymbolAtIndex(relocation.getSymbolIndex()));
|
||||
|
||||
// TODO: There may be multiple relocations at the same address.
|
||||
// The RelocationTable for retaining relocations needs to be revised to handle
|
||||
// this. At present only the last one will remain in the DB-backed address-based
|
||||
// table. (see GP-2128)
|
||||
program.getRelocationTable()
|
||||
.add(address, relocation.getType(),
|
||||
new long[] { relocation.getSymbolIndex() }, null,
|
||||
.add(address, status, relocation.getType(),
|
||||
new long[] { relocation.getSymbolIndex() }, byteLength,
|
||||
symbol != null ? symbol.getName() : "<null>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.reloc.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
@@ -992,8 +992,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
reloc.setType(relrRelocationType);
|
||||
}
|
||||
|
||||
Status status = Status.SKIPPED;
|
||||
int byteLength = 0;
|
||||
try {
|
||||
if (unableToApplyRelocs) {
|
||||
status = Status.FAILURE;
|
||||
ElfRelocationHandler.markAsError(program, relocAddr, type, symbolName,
|
||||
"missing symbol table", log);
|
||||
continue;
|
||||
@@ -1008,6 +1011,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
memory.convertToInitialized(relocBlock, (byte) 0);
|
||||
}
|
||||
catch (Exception e) {
|
||||
status = Status.FAILURE;
|
||||
Msg.error(this,
|
||||
"Unexpected exception while converting block to initialized", e);
|
||||
ElfRelocationHandler.markAsUninitializedMemory(program, relocAddr, type,
|
||||
@@ -1018,15 +1022,19 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
|
||||
if (context != null) {
|
||||
if (relrTypeUnknown) {
|
||||
status = Status.UNSUPPORTED;
|
||||
ElfRelocationHandler.markAsUnsupportedRelr(program, relocAddr);
|
||||
}
|
||||
else {
|
||||
context.processRelocation(reloc, relocAddr);
|
||||
RelocationResult result = context.processRelocation(reloc, relocAddr);
|
||||
byteLength = result.byteLength();
|
||||
status = result.status();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
if (type != 0) { // ignore if type 0 which is always NONE (no relocation performed)
|
||||
status = Status.FAILURE;
|
||||
log("Unable to perform relocation: Type = " + type + " (0x" +
|
||||
Long.toHexString(type) + ") at " + relocAddr + " (Symbol = " + symbolName +
|
||||
") - " + getMessage(e));
|
||||
@@ -1035,7 +1043,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
finally {
|
||||
// Save relocation data - uses original FileBytes
|
||||
program.getRelocationTable()
|
||||
.add(relocAddr, reloc.getType(), values, null, symbolName);
|
||||
.add(relocAddr, status, reloc.getType(), values, byteLength, symbolName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1063,19 +1071,22 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addFakeRelocTableEntry(Address address, int length) {
|
||||
public boolean addArtificialRelocTableEntry(Address address, int length) {
|
||||
try {
|
||||
Address maxAddr = address.addNoWrap(length - 1);
|
||||
RelocationTable relocationTable = program.getRelocationTable();
|
||||
List<Relocation> relocations = relocationTable.getRelocations(address);
|
||||
if (!relocations.isEmpty()) {
|
||||
return false;
|
||||
Msg.warn(this, "Artificial relocation at " + address +
|
||||
" conflicts with a previous relocation");
|
||||
}
|
||||
Address nextRelocAddr = relocationTable.getRelocationAddressAfter(address);
|
||||
if (nextRelocAddr == null || nextRelocAddr.compareTo(maxAddr) > 0) {
|
||||
relocationTable.add(address, 0, new long[0], null, null);
|
||||
return true;
|
||||
if (nextRelocAddr != null && nextRelocAddr.compareTo(maxAddr) <= 0) {
|
||||
Msg.warn(this,
|
||||
"Artificial relocation at " + address + " overlaps a previous relocation");
|
||||
}
|
||||
relocationTable.add(address, Status.APPLIED_OTHER, 0, null, length, null);
|
||||
return true;
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
Msg.error(this, "Failed to generate fake relocation data at " + address, e);
|
||||
|
||||
+63
-28
@@ -23,6 +23,7 @@ import java.util.*;
|
||||
import ghidra.app.util.MemoryBlockUtils;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.RelocationException;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.app.util.bin.format.macho.commands.*;
|
||||
import ghidra.app.util.bin.format.macho.commands.ExportTrie.ExportEntry;
|
||||
@@ -42,6 +43,8 @@ import ghidra.program.model.lang.Processor;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
@@ -1284,38 +1287,50 @@ public class MachoProgramBuilder {
|
||||
Address address = relocationMap.get(relocationInfo);
|
||||
MachoRelocation relocation = null;
|
||||
|
||||
RelocationResult result = RelocationResult.FAILURE;
|
||||
if (handler == null) {
|
||||
handleRelocationError(address, String.format(
|
||||
"No relocation handler for machine type 0x%x to process relocation at %s with type 0x%x",
|
||||
machoHeader.getCpuType(), address, relocationInfo.getType()));
|
||||
}
|
||||
else {
|
||||
relocation = handler.isPairedRelocation(relocationInfo)
|
||||
? new MachoRelocation(program, machoHeader, address, relocationInfo,
|
||||
iter.next())
|
||||
: new MachoRelocation(program, machoHeader, address, relocationInfo);
|
||||
try {
|
||||
relocation = handler.isPairedRelocation(relocationInfo)
|
||||
? new MachoRelocation(program, machoHeader, address, relocationInfo,
|
||||
iter.next())
|
||||
: new MachoRelocation(program, machoHeader, address, relocationInfo);
|
||||
handler.relocate(relocation);
|
||||
result = handler.relocate(relocation);
|
||||
|
||||
if (result.status() == Status.UNSUPPORTED) {
|
||||
handleRelocationError(address,
|
||||
String.format("Relocation type 0x%x at address %s is not supported",
|
||||
relocationInfo.getType(), address));
|
||||
}
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
handleRelocationError(address, String.format(
|
||||
"Error accessing memory at address %s. Relocation failed.", address));
|
||||
"Relocation failure at address %s: error accessing memory.", address));
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
handleRelocationError(address,
|
||||
String.format("Relocation type 0x%x at address %s is not supported: %s",
|
||||
relocationInfo.getType(), address, e.getMessage()));
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
handleRelocationError(address,
|
||||
String.format("Error computing relocation at address %s.", address));
|
||||
catch (RelocationException e) {
|
||||
handleRelocationError(address, String.format(
|
||||
"Relocation failure at address %s: %s", address, e.getMessage()));
|
||||
}
|
||||
catch (Exception e) { // handle unexpected exceptions
|
||||
String msg = e.getMessage();
|
||||
if (msg == null) {
|
||||
msg = e.toString();
|
||||
}
|
||||
msg = String.format("Relocation failure at address %s: %s", address, msg);
|
||||
handleRelocationError(address, msg);
|
||||
Msg.error(this, msg, e);
|
||||
}
|
||||
}
|
||||
program.getRelocationTable()
|
||||
.add(address, relocationInfo.getType(), new long[] { relocationInfo.getValue(),
|
||||
.add(address, result.status(), relocationInfo.getType(),
|
||||
new long[] { relocationInfo.getValue(),
|
||||
relocationInfo.getLength(), relocationInfo.isPcRelocated() ? 1 : 0,
|
||||
relocationInfo.isExternal() ? 1 : 0, relocationInfo.isScattered() ? 1 : 0 },
|
||||
null, relocation.getTargetDescription());
|
||||
result.byteLength(), relocation.getTargetDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1325,7 +1340,7 @@ public class MachoProgramBuilder {
|
||||
* @param address The address of the relocation error
|
||||
* @param message The error message
|
||||
*/
|
||||
private void handleRelocationError(Address address, String message) {
|
||||
private void handleRelocationError(Address address, String message) {
|
||||
program.getBookmarkManager()
|
||||
.setBookmark(address, BookmarkType.ERROR, "Relocations", message);
|
||||
log.appendMsg(message);
|
||||
@@ -1783,10 +1798,21 @@ public class MachoProgramBuilder {
|
||||
}
|
||||
|
||||
if (!start || !program.getRelocationTable().hasRelocation(chainLoc)) {
|
||||
addRelocationTableEntry(chainLoc,
|
||||
(start ? 0x8000 : 0x4000) | (isAuthenticated ? 4 : 0) | (isBound ? 2 : 0) | 1,
|
||||
newChainValue, symName);
|
||||
DyldChainedPtr.setChainValue(memory, chainLoc, pointerFormat, newChainValue);
|
||||
int byteLength = 0;
|
||||
Status status = Status.FAILURE;
|
||||
try {
|
||||
RelocationResult result =
|
||||
DyldChainedPtr.setChainValue(memory, chainLoc, pointerFormat,
|
||||
newChainValue);
|
||||
status = result.status();
|
||||
byteLength = result.byteLength();
|
||||
}
|
||||
finally {
|
||||
addRelocationTableEntry(chainLoc, status,
|
||||
(start ? 0x8000 : 0x4000) | (isAuthenticated ? 4 : 0) | (isBound ? 2 : 0) |
|
||||
1,
|
||||
newChainValue, byteLength, symName);
|
||||
}
|
||||
}
|
||||
// delay creating data until after memory has been changed
|
||||
unchainedLocList.add(chainLoc);
|
||||
@@ -1797,11 +1823,12 @@ public class MachoProgramBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void addRelocationTableEntry(Address chainLoc, int type, long chainValue, String name) {
|
||||
private void addRelocationTableEntry(Address chainLoc, Status status, int type, long chainValue,
|
||||
int byteLength, String name) {
|
||||
if (shouldAddChainedFixupsRelocations) {
|
||||
// Add entry to relocation table for the pointer fixup
|
||||
program.getRelocationTable()
|
||||
.add(chainLoc, type, new long[] { chainValue }, null, name);
|
||||
.add(chainLoc, status, type, new long[] { chainValue }, byteLength, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1871,12 +1898,20 @@ public class MachoProgramBuilder {
|
||||
// Add entry to relocation table for the pointer fixup
|
||||
byte origBytes[] = new byte[8];
|
||||
memory.getBytes(pointerAddr, origBytes);
|
||||
program.getRelocationTable()
|
||||
.add(pointerAddr, (int) fixedPointerType, new long[] { fixedPointerValue },
|
||||
origBytes, null);
|
||||
|
||||
// Fixup the pointer
|
||||
memory.setLong(pointerAddr, fixedPointerValue);
|
||||
boolean success = false;
|
||||
try {
|
||||
// Fixup the pointer
|
||||
memory.setLong(pointerAddr, fixedPointerValue);
|
||||
success = true;
|
||||
}
|
||||
finally {
|
||||
Status status = success ? Status.APPLIED : Status.FAILURE;
|
||||
program.getRelocationTable()
|
||||
.add(pointerAddr, status, (int) fixedPointerType,
|
||||
new long[] { fixedPointerValue },
|
||||
origBytes, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,7 @@ import ghidra.program.model.data.DataUtilities;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.DataConverter;
|
||||
import ghidra.util.LittleEndianDataConverter;
|
||||
@@ -302,20 +303,20 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
||||
|
||||
for (RelocationFixup relocationFixup : relocationFixups) {
|
||||
SegmentedAddress relocationAddress = relocationFixup.address();
|
||||
Status status = Status.FAILURE;
|
||||
try {
|
||||
byte[] origBytes = new byte[2];
|
||||
memory.getBytes(relocationAddress, origBytes);
|
||||
memory.setShort(relocationAddress, (short) relocationFixup.segment());
|
||||
|
||||
// Add to relocation table
|
||||
program.getRelocationTable()
|
||||
.add(relocationAddress, 0, new long[] { relocationAddress.getSegment(),
|
||||
relocationAddress.getSegmentOffset() }, origBytes, null);
|
||||
status = Status.APPLIED;
|
||||
}
|
||||
catch (AddressOutOfBoundsException | MemoryAccessException e) {
|
||||
catch (MemoryAccessException e) {
|
||||
log.appendMsg(String.format("Failed to apply relocation: %s (%s)",
|
||||
relocationAddress, e.getMessage()));
|
||||
}
|
||||
|
||||
// Add to relocation table
|
||||
program.getRelocationTable()
|
||||
.add(relocationAddress, status, 0, new long[] { relocationAddress.getSegment(),
|
||||
relocationAddress.getSegmentOffset() }, 2, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import ghidra.program.model.data.StringDataType;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
@@ -655,15 +656,15 @@ public class NeLoader extends AbstractOrdinalSupportLoader {
|
||||
}
|
||||
|
||||
int relocType = reloc.getType();
|
||||
int byteLength = SegmentRelocation.TYPE_LENGTHS[relocType];
|
||||
|
||||
do {
|
||||
// TODO: it appears that offset may be a far-offset and not always a segment-offset
|
||||
SegmentedAddress address = space.getAddress(segment, offset);
|
||||
try {
|
||||
byte[] bytes = new byte[SegmentRelocation.TYPE_LENGTHS[relocType]];
|
||||
memory.getBytes(address, bytes);
|
||||
|
||||
relocTable.add(address, relocType, reloc.getValues(), bytes, null);
|
||||
offset = relocate(memory, reloc, address, relocAddr);
|
||||
relocTable.add(address, Status.APPLIED, relocType, reloc.getValues(),
|
||||
byteLength, null);
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
log.appendMsg("Relocation does not exist in memory: " + relocAddr);
|
||||
|
||||
@@ -32,6 +32,7 @@ import ghidra.program.model.data.Undefined;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.DataConverter;
|
||||
@@ -268,8 +269,9 @@ public class OmfLoader extends AbstractProgramWrapperLoader {
|
||||
}
|
||||
long[] values = new long[1];
|
||||
values[0] = finalvalue;
|
||||
program.getRelocationTable().add(state.locAddress, state.locationType, values,
|
||||
origbytes, null);
|
||||
program.getRelocationTable()
|
||||
.add(state.locAddress, Status.APPLIED,
|
||||
state.locationType, values, origbytes, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
@@ -305,7 +306,8 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
int baseAddr = reloc.getVirtualAddress();
|
||||
for (int i = 0; i < reloc.getCount(); ++i) {
|
||||
long addr = optionalHeader.getImageBase() + baseAddr + reloc.getOffset(i);
|
||||
relocTable.add(space.getAddress(addr), reloc.getType(i), null, null, null);
|
||||
relocTable.add(space.getAddress(addr), Status.SKIPPED, reloc.getType(i), null, null,
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ import java.util.Iterator;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.util.XmlProgramUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
@@ -42,15 +44,14 @@ class RelocationTableXmlMgr {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
void read(XmlPullParser parser, TaskMonitor monitor) throws CancelledException {
|
||||
void read(XmlPullParser parser, TaskMonitor monitor)
|
||||
throws SAXParseException, CancelledException {
|
||||
RelocationTable relocTable = program.getRelocationTable();
|
||||
AddressFactory factory = program.getAddressFactory();
|
||||
|
||||
XmlElement element = parser.next();
|
||||
while (true) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
monitor.checkCanceled();
|
||||
element = parser.next();
|
||||
if (!element.getName().equals("RELOCATION")) {
|
||||
break;
|
||||
@@ -70,7 +71,29 @@ class RelocationTableXmlMgr {
|
||||
byte[] bytes = unpackBytes(element.getAttribute("BYTES")); // optional
|
||||
String symbolName = element.getAttribute("SYMBOL_NAME"); // optional
|
||||
|
||||
relocTable.add(addr, type, values, bytes, symbolName);
|
||||
String statusAttr = element.getAttribute("STATUS");
|
||||
Status status = Status.UNKNOWN;
|
||||
if (statusAttr != null) {
|
||||
try {
|
||||
status = Status.valueOf(statusAttr.toUpperCase());
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new SAXParseException("Invalid relocation status: " + statusAttr,
|
||||
null, null, parser.getLineNumber(), parser.getColumnNumber());
|
||||
}
|
||||
}
|
||||
if (bytes == null) {
|
||||
if (status != null && status.hasBytes()) {
|
||||
log.appendMsg("Relocation at " + addrStr +
|
||||
" missing required bytes - forced UNKNOWN status.");
|
||||
status = Status.UNKNOWN;
|
||||
}
|
||||
}
|
||||
else if (status == null) {
|
||||
status = type == 0 ? Status.APPLIED_OTHER : Status.APPLIED;
|
||||
}
|
||||
|
||||
relocTable.add(addr, status, type, values, bytes, symbolName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.appendException(e);
|
||||
@@ -83,6 +106,9 @@ class RelocationTableXmlMgr {
|
||||
}
|
||||
|
||||
private long[] unpackLongs(String attrValue) {
|
||||
if (attrValue == null) {
|
||||
return null;
|
||||
}
|
||||
StringTokenizer st = new StringTokenizer(attrValue, ",");
|
||||
long[] values = new long[st.countTokens()];
|
||||
int index = 0;
|
||||
|
||||
@@ -1704,9 +1704,10 @@ public class FlatProgramAPI {
|
||||
* @param address the address at which to create a new Data object.
|
||||
* @param datatype the Data Type that describes the type of Data object to create.
|
||||
* @return the newly created Data object
|
||||
* @throws Exception if there is any exception
|
||||
* @throws CodeUnitInsertionException if a conflicting code unit already exists
|
||||
*/
|
||||
public final Data createData(Address address, DataType datatype) throws Exception {
|
||||
public final Data createData(Address address, DataType datatype)
|
||||
throws CodeUnitInsertionException {
|
||||
Listing listing = currentProgram.getListing();
|
||||
Data d = listing.getDefinedDataAt(address);
|
||||
if (d != null) {
|
||||
|
||||
@@ -160,8 +160,12 @@
|
||||
|
||||
<!ELEMENT RELOCATION EMPTY>
|
||||
<!ATTLIST RELOCATION ADDRESS CDATA #REQUIRED>
|
||||
<!ATTLIST RELOCATION STATUS ( UNKNOWN | SKIPPED | UNSUPPORTED | FAILURE | PARTIAL | APPLIED | APPLIED_OTHER ) #IMPLIED>
|
||||
<!-- STATUS defaults to APPLIED if BYTES specified and TYPE is non-zero -->
|
||||
<!-- STATUS defaults to APPLIED_OTHER if BYTES specified and TYPE is zero -->
|
||||
<!-- STATUS defaults to UNKNOWN if BYTES are not specified -->
|
||||
<!ATTLIST RELOCATION TYPE CDATA #REQUIRED>
|
||||
<!ATTLIST RELOCATION VALUE CDATA #REQUIRED>
|
||||
<!ATTLIST RELOCATION VALUE CDATA #IMPLIED>
|
||||
<!ATTLIST RELOCATION BYTES CDATA #IMPLIED>
|
||||
<!ATTLIST RELOCATION SYMBOL_NAME CDATA #IMPLIED>
|
||||
|
||||
|
||||
+15
-30
@@ -974,42 +974,27 @@ public class DexHeaderFormatMarkup {
|
||||
}
|
||||
|
||||
String string = stringDataItem.getString();
|
||||
DataType stringDataType = stringDataItem.toDataType();
|
||||
api.createData(stringDataAddress, stringDataType);
|
||||
api.setPlateComment(stringDataAddress,
|
||||
Integer.toHexString(index) + "\n" + string.trim());
|
||||
fragmentManager.stringDataAddressSet.add(stringDataAddress,
|
||||
stringDataAddress.add(stringDataType.getLength() - 1));
|
||||
|
||||
try {
|
||||
DataType stringDataType = stringDataItem.toDataType();
|
||||
api.createData(stringDataAddress, stringDataType);
|
||||
api.setPlateComment(stringDataAddress,
|
||||
Integer.toHexString(index) + "\n" + string.trim());
|
||||
fragmentManager.stringDataAddressSet.add(stringDataAddress,
|
||||
stringDataAddress.add(stringDataType.getLength() - 1));
|
||||
|
||||
createStringSymbol(stringDataAddress, string, "strings");
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
log.appendException(e); // Report the exception but keep going
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
log.appendException(e);
|
||||
}
|
||||
createStringSymbol(stringDataAddress, string, "strings");
|
||||
|
||||
// markup string Id items
|
||||
DataType dataType = item.toDataType();
|
||||
try {
|
||||
Data data = api.createData(address, dataType);
|
||||
fragmentManager.stringsDataSet.add(address, address.add(dataType.getLength() - 1));
|
||||
|
||||
api.setPlateComment(address, "String Index: 0x" + Integer.toHexString(index) +
|
||||
"\nString: " + string.trim() + "\nString Data Address: " + stringDataAddress);
|
||||
createStringSymbol(address, string, "string_data");
|
||||
Data data = api.createData(address, dataType);
|
||||
fragmentManager.stringsDataSet.add(address, address.add(dataType.getLength() - 1));
|
||||
|
||||
api.setPlateComment(address, "String Index: 0x" + Integer.toHexString(index) +
|
||||
"\nString: " + string.trim() + "\nString Data Address: " + stringDataAddress);
|
||||
createStringSymbol(address, string, "string_data");
|
||||
|
||||
api.createMemoryReference(data, stringDataAddress, RefType.DATA);
|
||||
|
||||
api.createMemoryReference(data, stringDataAddress, RefType.DATA);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
log.appendException(e); // Report the exception but keep going
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
log.appendException(e);
|
||||
}
|
||||
++index;
|
||||
|
||||
address = address.add(dataType.getLength());
|
||||
|
||||
+10
-7
@@ -22,11 +22,8 @@ import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.file.formats.android.dex.util.DexUtil;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
@@ -73,11 +70,17 @@ public class StringDataItem implements StructConverter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
public DataType toDataType() {
|
||||
Structure structure = new StructureDataType("string_data_item_" + actualLength, 0);
|
||||
structure.add(new ArrayDataType(BYTE, lebLength, BYTE.getLength()), "utf16_size", null);
|
||||
structure.add(UTF8, actualLength, "data", null);
|
||||
structure.setCategoryPath(new CategoryPath("/dex/string_data_item"));
|
||||
try {
|
||||
structure.setCategoryPath(new CategoryPath("/dex/string_data_item"));
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// will not occur for new StructureDataType
|
||||
throw new AssertException(e);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -107,9 +107,11 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
||||
* TypeDefSettingsDefinition. Added DataTypeManager versioning
|
||||
* support. Added support for auto-named TypeDef datatypes.
|
||||
* Transitioned string data translation storage to use address-based
|
||||
* property map (StringTranslations).
|
||||
* property map (StringTranslations).
|
||||
* 19-Jan-2023 - version 26 Improved relocation data records to incorporate status and
|
||||
* byte-length when original FileBytes should be used.
|
||||
*/
|
||||
static final int DB_VERSION = 25;
|
||||
static final int DB_VERSION = 26;
|
||||
|
||||
/**
|
||||
* UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the
|
||||
@@ -129,6 +131,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
||||
public static final int EXTERNAL_FUNCTIONS_ADDED_VERSION = 17;
|
||||
public static final int COMPOUND_VARIABLE_STORAGE_ADDED_VERSION = 18;
|
||||
public static final int AUTO_PARAMETERS_ADDED_VERSION = 19;
|
||||
public static final int RELOCATION_STATUS_ADDED_VERSION = 26;
|
||||
|
||||
private static final String DATA_MAP_TABLE_NAME = "Program";
|
||||
|
||||
|
||||
+236
-23
@@ -16,12 +16,19 @@
|
||||
package ghidra.program.database.reloc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
abstract class RelocationDBAdapter {
|
||||
@@ -32,30 +39,46 @@ abstract class RelocationDBAdapter {
|
||||
// V3 - added Bytes
|
||||
// V4 - added Name, switched Value to binary coded long[] from long
|
||||
// V5 - moved Addr key to column and indexed, use one-up key
|
||||
// V6 - added FLAGS columns (status and optional length)
|
||||
|
||||
final static int ADDR_COL = 0; // indexed
|
||||
final static int TYPE_COL = 1;
|
||||
final static int VALUE_COL = 2;
|
||||
final static int BYTES_COL = 3;
|
||||
final static int SYMBOL_NAME_COL = 4;
|
||||
final static int FLAGS_COL = 1; // includes status enum and optional length when bytes==null
|
||||
final static int TYPE_COL = 2;
|
||||
final static int VALUE_COL = 3; // binary coded long[]
|
||||
final static int BYTES_COL = 4; // null defers to FileBytes (see length)
|
||||
final static int SYMBOL_NAME_COL = 5;
|
||||
|
||||
/**
|
||||
* FLAGS bit encoding:
|
||||
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
* | | length | status |
|
||||
* status: Relocation.Status enum index
|
||||
* length: Optional byte-length used when bytes is null (0..31)
|
||||
*/
|
||||
final static int STATUS_FLAGS_MASK = 0x7;
|
||||
final static int LENGTH_FLAGS_MASK = 0xF;
|
||||
final static int LENGTH_FLAGS_SHIFT = 3;
|
||||
final static int LENGTH_MAX = 31;
|
||||
|
||||
final static String TABLE_NAME = "Relocations";
|
||||
|
||||
final static Schema SCHEMA = new Schema(
|
||||
RelocationDBAdapterV5.VERSION, "Index", new Field[] { LongField.INSTANCE, IntField.INSTANCE,
|
||||
RelocationDBAdapterV6.VERSION, "Index",
|
||||
new Field[] { LongField.INSTANCE, ByteField.INSTANCE, IntField.INSTANCE,
|
||||
BinaryField.INSTANCE, BinaryField.INSTANCE, StringField.INSTANCE },
|
||||
new String[] { "Address", "Type", "Values", "Bytes", "Symbol Name" });
|
||||
new String[] { "Address", "Status", "Type", "Values", "Bytes", "Symbol Name" });
|
||||
|
||||
static RelocationDBAdapter getAdapter(DBHandle dbHandle, int openMode, AddressMap addrMap,
|
||||
TaskMonitor monitor) throws VersionException, IOException {
|
||||
try {
|
||||
return new RelocationDBAdapterV5(dbHandle, addrMap, openMode == DBConstants.CREATE);
|
||||
return new RelocationDBAdapterV6(dbHandle, addrMap, openMode == DBConstants.CREATE);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
|
||||
throw e;
|
||||
}
|
||||
RelocationDBAdapter adapter = findReadOnlyAdapter(dbHandle, addrMap);
|
||||
RelocationDBAdapter adapter =
|
||||
findReadOnlyAdapter(dbHandle, addrMap);
|
||||
if (openMode == DBConstants.UPGRADE) {
|
||||
adapter = upgrade(dbHandle, addrMap, adapter, monitor);
|
||||
}
|
||||
@@ -65,6 +88,12 @@ abstract class RelocationDBAdapter {
|
||||
|
||||
private static RelocationDBAdapter findReadOnlyAdapter(DBHandle handle, AddressMap addrMap)
|
||||
throws IOException, VersionException {
|
||||
try {
|
||||
return new RelocationDBAdapterV5(handle, addrMap);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
// try the next version
|
||||
}
|
||||
try {
|
||||
return new RelocationDBAdapterV4(handle, addrMap);
|
||||
}
|
||||
@@ -102,7 +131,8 @@ abstract class RelocationDBAdapter {
|
||||
try {
|
||||
tmpHandle.startTransaction();
|
||||
|
||||
RelocationDBAdapter tmpAdapter = new RelocationDBAdapterV5(tmpHandle, addrMap, true);
|
||||
RelocationDBAdapter tmpAdapter =
|
||||
new RelocationDBAdapterV6(tmpHandle, addrMap, true);
|
||||
RecordIterator iter = oldAdapter.iterator();
|
||||
while (iter.hasNext()) {
|
||||
DBRecord rec = iter.next();
|
||||
@@ -110,19 +140,20 @@ abstract class RelocationDBAdapter {
|
||||
Address addr = oldAddrMap.decodeAddress(rec.getLongValue(ADDR_COL));
|
||||
BinaryCodedField values =
|
||||
new BinaryCodedField((BinaryField) rec.getFieldValue(VALUE_COL));
|
||||
tmpAdapter.add(addr, rec.getIntValue(TYPE_COL),
|
||||
tmpAdapter.add(addr, rec.getByteValue(FLAGS_COL), rec.getIntValue(TYPE_COL),
|
||||
values.getLongArray(), rec.getBinaryData(BYTES_COL),
|
||||
rec.getString(SYMBOL_NAME_COL));
|
||||
}
|
||||
|
||||
dbHandle.deleteTable(TABLE_NAME);
|
||||
|
||||
RelocationDBAdapterV5 newAdapter = new RelocationDBAdapterV5(dbHandle, addrMap, true);
|
||||
RelocationDBAdapterV6 newAdapter =
|
||||
new RelocationDBAdapterV6(dbHandle, addrMap, true);
|
||||
|
||||
iter = tmpAdapter.iterator();
|
||||
while (iter.hasNext()) {
|
||||
DBRecord rec = iter.next();
|
||||
newAdapter.add(rec);
|
||||
newAdapter.put(rec);
|
||||
}
|
||||
return newAdapter;
|
||||
}
|
||||
@@ -131,21 +162,61 @@ abstract class RelocationDBAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Adapter Required Methods
|
||||
//==================================================================================================
|
||||
/**
|
||||
* Generate flags value for specified status and original bytes length for relocation.
|
||||
* @param status relocation status
|
||||
* @param byteLength byte length (specify 0 if bytes length is known, otherwise 1..31)
|
||||
* @return flags value
|
||||
*/
|
||||
static byte getFlags(Relocation.Status status, int byteLength) {
|
||||
if (byteLength < 0 || byteLength > LENGTH_MAX) {
|
||||
throw new IllegalArgumentException("unsupport byte-length: " + byteLength);
|
||||
}
|
||||
int flags = (status.getValue() & STATUS_FLAGS_MASK);
|
||||
flags |= byteLength << LENGTH_FLAGS_SHIFT;
|
||||
return (byte) flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status specified by the relocation flags.
|
||||
* @param flags relocation flags
|
||||
* @return relocation status
|
||||
*/
|
||||
static Status getStatus(byte flags) {
|
||||
try {
|
||||
return Status.getStatus(flags & STATUS_FLAGS_MASK);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return Status.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the byte length specified by the relocation flags. This length should only be used
|
||||
* if stored bytes is null and relocation has an appropriate status.
|
||||
* @param flags relocation flags
|
||||
* @return byte length specified by the relocation flags (0..31)
|
||||
*/
|
||||
static int getByteLength(byte flags) {
|
||||
return (flags >> LENGTH_FLAGS_SHIFT) & LENGTH_FLAGS_MASK;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Adapter Required Methods
|
||||
//==================================================================================================
|
||||
|
||||
/**
|
||||
* Add new relocation record
|
||||
* @param addr relocation address
|
||||
* @param flags encoded flags (status, length), see {@link #getFlags(Status, int)}.
|
||||
* @param type relocation type
|
||||
* @param values relocation value (e.g., symbol index)
|
||||
* @param bytes original memory bytes
|
||||
* @param symbolName symbol name
|
||||
* @throws IOException if a database error occurs
|
||||
*/
|
||||
abstract void add(Address addr, int type, long[] values, byte[] bytes, String symbolName)
|
||||
throws IOException;
|
||||
abstract void add(Address addr, byte flags, int type, long[] values, byte[] bytes,
|
||||
String symbolName) throws IOException;
|
||||
|
||||
/**
|
||||
* Iterator over all records in address order.
|
||||
@@ -183,9 +254,151 @@ abstract class RelocationDBAdapter {
|
||||
*/
|
||||
abstract DBRecord adaptRecord(DBRecord rec);
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
// Complex Upgrade Methods
|
||||
//==================================================================================================
|
||||
|
||||
/**
|
||||
* Perform relocation data migration following an adapter upgrade from a version prior to
|
||||
* V6 (see {@link ProgramDB#RELOCATION_STATUS_ADDED_VERSION}) It is assumed that records have
|
||||
* already been migrated during the table upgrade with a {@link Status#UNKNOWN} status.
|
||||
* @param adapter latest relocation adapter which permits record updates
|
||||
* @param program program which is "ready"
|
||||
* @param monitor task monitor
|
||||
* @throws IOException if IO error occurs
|
||||
* @throws CancelledException if task cancelled
|
||||
*/
|
||||
static void preV6DataMigrationUpgrade(RelocationDBAdapter adapter, Program program,
|
||||
TaskMonitor monitor) throws IOException, CancelledException {
|
||||
|
||||
if (!(adapter instanceof RelocationDBAdapterV6 latestAdapter)) {
|
||||
throw new AssertException("latest relocation adapter version expected");
|
||||
}
|
||||
|
||||
AddressMap addressMap = program.getAddressMap();
|
||||
Memory memory = program.getMemory();
|
||||
AddressSetView loadedAndInitializedAddressSet = memory.getLoadedAndInitializedAddressSet();
|
||||
|
||||
ArrayList<DBRecord> list = new ArrayList<>();
|
||||
RecordIterator recIter = latestAdapter.iterator();
|
||||
while (recIter.hasNext()) {
|
||||
list.add(recIter.next());
|
||||
}
|
||||
|
||||
// Sort on address and key order
|
||||
Collections.sort(list, (r1,r2) -> {
|
||||
Address a1 = addressMap.decodeAddress(r1.getLongValue(ADDR_COL));
|
||||
Address a2 = addressMap.decodeAddress(r2.getLongValue(ADDR_COL));
|
||||
int c = a1.compareTo(a2);
|
||||
if (c == 0) { // assumes positive keys only
|
||||
c = Long.compare(r1.getKey(), r2.getKey());
|
||||
}
|
||||
return c;
|
||||
});
|
||||
|
||||
// Update status/length of each relocation record
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
monitor.checkCanceled();
|
||||
DBRecord rec = list.get(i);
|
||||
int byteLength = 0;
|
||||
Status status;
|
||||
Address relocAddr = addressMap.decodeAddress(rec.getLongValue(ADDR_COL));
|
||||
byte[] bytes = rec.getBinaryData(BYTES_COL);
|
||||
if (!loadedAndInitializedAddressSet.contains(relocAddr)) {
|
||||
status = Status.FAILURE;
|
||||
}
|
||||
else if (bytes != null) {
|
||||
status = rec.getIntValue(TYPE_COL) == 0 ? Status.APPLIED_OTHER : Status.APPLIED;
|
||||
}
|
||||
else {
|
||||
byteLength = computeOriginalFileBytesLength(list, relocAddr, i, program);
|
||||
if (byteLength < 0) {
|
||||
status = Status.PARTIAL;
|
||||
byteLength = 0;
|
||||
}
|
||||
else if (byteLength == 0) {
|
||||
status = Status.UNKNOWN;
|
||||
}
|
||||
else {
|
||||
status = rec.getIntValue(TYPE_COL) == 0 ? Status.APPLIED_OTHER
|
||||
: Status.APPLIED;
|
||||
}
|
||||
}
|
||||
rec.setByteValue(FLAGS_COL, getFlags(status, byteLength));
|
||||
latestAdapter.put(rec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a relocation byte length which will be no greater than the default length
|
||||
* (see {@link RelocationManager#getDefaultOriginalByteLength(Program)} which should not
|
||||
* overlap a subsequent relocation record.
|
||||
* <p>
|
||||
* NOTE: it is possible for a patched instruction to interfere with this logic, however
|
||||
* the result should be no worse than the previously over-extended relocation byte range.
|
||||
*
|
||||
* @param list sorted relocation list
|
||||
* @param relocAddr relocation address
|
||||
* @param index relocation index within list
|
||||
* @param program program containing relocations
|
||||
* @return number of original bytes modified or -1 if there is a subsequent relocation at the
|
||||
* same address
|
||||
* @throws IOException if an IO error occurs
|
||||
*/
|
||||
private static int computeOriginalFileBytesLength(ArrayList<DBRecord> list, Address relocAddr,
|
||||
int index, Program program) throws IOException {
|
||||
|
||||
AddressSpace space = relocAddr.getAddressSpace();
|
||||
AddressMap addrMap = program.getAddressMap();
|
||||
Memory memory = program.getMemory();
|
||||
|
||||
int defaultLength = RelocationManager.getDefaultOriginalByteLength(program);
|
||||
|
||||
int nextIndex = index + 1;
|
||||
if (nextIndex < list.size()) {
|
||||
DBRecord nextRec = list.get(nextIndex);
|
||||
Address nextAddr = addrMap.decodeAddress(nextRec.getLongValue(ADDR_COL));
|
||||
if (nextAddr.getAddressSpace().equals(relocAddr.getAddressSpace())) {
|
||||
defaultLength = (int) Math.min(defaultLength, nextAddr.subtract(relocAddr));
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Limit relocation length based upon end of address space
|
||||
try {
|
||||
relocAddr.addNoWrap(defaultLength - 1); // test for valid length
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
defaultLength = (int) space.getMaxAddress().subtract(relocAddr) + 1;
|
||||
}
|
||||
|
||||
// Obtain original and current memory bytes at relocation address for comparison
|
||||
byte[] originalBytes = RelocationManager.getOriginalBytes(memory, relocAddr, defaultLength);
|
||||
byte[] currentBytes = new byte[defaultLength];
|
||||
try {
|
||||
defaultLength = memory.getBytes(relocAddr, currentBytes);
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
throw new AssertException(e); // unexpected - already checked relocAddr
|
||||
}
|
||||
|
||||
// Indentify modification length
|
||||
while (defaultLength != 0) {
|
||||
int byteIndex = defaultLength - 1;
|
||||
if (originalBytes[byteIndex] != currentBytes[byteIndex]) {
|
||||
break;
|
||||
}
|
||||
--defaultLength;
|
||||
}
|
||||
return defaultLength;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
||||
class RecordIteratorAdapter implements RecordIterator {
|
||||
RecordIterator it;
|
||||
|
||||
+2
-1
@@ -43,7 +43,8 @@ class RelocationDBAdapterNoTable extends RelocationDBAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
void add(Address addrKey, int type, long[] values, byte[] bytes, String symbolName) {
|
||||
void add(Address addrKey, byte flags, int type, long[] values, byte[] bytes,
|
||||
String symbolName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -22,6 +22,7 @@ import ghidra.program.database.map.AddressKeyRecordIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
class RelocationDBAdapterV1 extends RelocationDBAdapter {
|
||||
@@ -29,6 +30,7 @@ class RelocationDBAdapterV1 extends RelocationDBAdapter {
|
||||
|
||||
private final static int V1_TYPE_COL = 0;
|
||||
|
||||
/* Do not remove the following commented out schema! It shows the version 1 relocation table schema. */
|
||||
// final static Schema SCHEMA = new Schema(
|
||||
// RelocationDBAdapterV1.VERSION, "Address", new Field[] { IntField.INSTANCE },
|
||||
// new String[] { "Type" });
|
||||
@@ -43,8 +45,8 @@ class RelocationDBAdapterV1 extends RelocationDBAdapter {
|
||||
* @throws IOException if database IO error occurs
|
||||
* @throws VersionException throw if table schema is not V1
|
||||
*/
|
||||
RelocationDBAdapterV1(DBHandle handle, AddressMap addrMap) throws IOException,
|
||||
VersionException {
|
||||
RelocationDBAdapterV1(DBHandle handle, AddressMap addrMap)
|
||||
throws IOException, VersionException {
|
||||
this.addrMap = addrMap;
|
||||
relocTable = handle.getTable(TABLE_NAME);
|
||||
if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) {
|
||||
@@ -53,7 +55,8 @@ class RelocationDBAdapterV1 extends RelocationDBAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
void add(Address addrKey, int type, long[] values, byte[] bytes, String symbolName) {
|
||||
void add(Address addrKey, byte flags, int type, long[] values, byte[] bytes,
|
||||
String symbolName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -88,6 +91,7 @@ class RelocationDBAdapterV1 extends RelocationDBAdapter {
|
||||
}
|
||||
DBRecord newRec = SCHEMA.createRecord(rec.getKey());
|
||||
newRec.setLongValue(ADDR_COL, rec.getKey()); // key was encoded address
|
||||
newRec.setByteValue(FLAGS_COL, getFlags(Status.UNKNOWN, 0));
|
||||
newRec.setIntValue(TYPE_COL, rec.getIntValue(V1_TYPE_COL));
|
||||
return newRec;
|
||||
}
|
||||
|
||||
+7
-3
@@ -22,6 +22,7 @@ import ghidra.program.database.map.AddressKeyRecordIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
class RelocationDBAdapterV2 extends RelocationDBAdapter {
|
||||
@@ -30,6 +31,7 @@ class RelocationDBAdapterV2 extends RelocationDBAdapter {
|
||||
private final static int V2_TYPE_COL = 0;
|
||||
private final static int V2_VALUE_COL = 1;
|
||||
|
||||
/* Do not remove the following commented out schema! It shows the version 2 relocation table schema. */
|
||||
// final static Schema SCHEMA = new Schema(
|
||||
// RelocationDBAdapterV2.VERSION, "Address", new Field[] { IntField.INSTANCE, LongField.INSTANCE },
|
||||
// new String[] { "Type", "Values" });
|
||||
@@ -44,8 +46,8 @@ class RelocationDBAdapterV2 extends RelocationDBAdapter {
|
||||
* @throws IOException if database IO error occurs
|
||||
* @throws VersionException throw if table schema is not V2
|
||||
*/
|
||||
RelocationDBAdapterV2(DBHandle handle, AddressMap addrMap) throws IOException,
|
||||
VersionException {
|
||||
RelocationDBAdapterV2(DBHandle handle, AddressMap addrMap)
|
||||
throws IOException, VersionException {
|
||||
this.addrMap = addrMap;
|
||||
relocTable = handle.getTable(TABLE_NAME);
|
||||
if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) {
|
||||
@@ -54,7 +56,8 @@ class RelocationDBAdapterV2 extends RelocationDBAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
void add(Address addrKey, int type, long[] values, byte[] bytes, String symbolName) {
|
||||
void add(Address addrKey, byte flags, int type, long[] values, byte[] bytes,
|
||||
String symbolName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -89,6 +92,7 @@ class RelocationDBAdapterV2 extends RelocationDBAdapter {
|
||||
}
|
||||
DBRecord newRec = SCHEMA.createRecord(rec.getKey());
|
||||
newRec.setLongValue(ADDR_COL, rec.getKey()); // key was encoded address
|
||||
newRec.setByteValue(FLAGS_COL, getFlags(Status.UNKNOWN, 0));
|
||||
newRec.setIntValue(TYPE_COL, rec.getIntValue(V2_TYPE_COL));
|
||||
long[] values = new long[] { rec.getLongValue(V2_VALUE_COL) };
|
||||
newRec.setField(VALUE_COL, new BinaryCodedField(values));
|
||||
|
||||
+6
-3
@@ -22,6 +22,7 @@ import ghidra.program.database.map.AddressKeyRecordIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
class RelocationDBAdapterV3 extends RelocationDBAdapter {
|
||||
@@ -32,6 +33,7 @@ class RelocationDBAdapterV3 extends RelocationDBAdapter {
|
||||
private final static int V3_VALUE_COL = 1;
|
||||
private final static int V3_BYTES_COL = 2;
|
||||
|
||||
/* Do not remove the following commented out schema! It shows the version 3 relocation table schema. */
|
||||
// final static Schema SCHEMA = new Schema(
|
||||
// RelocationDBAdapterV3.VERSION, "Address", new Field[] { IntField.INSTANCE,
|
||||
// BinaryField.INSTANCE, BinaryField.INSTANCE },
|
||||
@@ -47,8 +49,8 @@ class RelocationDBAdapterV3 extends RelocationDBAdapter {
|
||||
* @throws IOException if database IO error occurs
|
||||
* @throws VersionException throw if table schema is not V3
|
||||
*/
|
||||
RelocationDBAdapterV3(DBHandle handle, AddressMap addrMap) throws IOException,
|
||||
VersionException {
|
||||
RelocationDBAdapterV3(DBHandle handle, AddressMap addrMap)
|
||||
throws IOException, VersionException {
|
||||
this.addrMap = addrMap;
|
||||
relocTable = handle.getTable(TABLE_NAME);
|
||||
if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) {
|
||||
@@ -57,7 +59,7 @@ class RelocationDBAdapterV3 extends RelocationDBAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
void add(Address addrKey, int type, long[] values, byte[] bytes, String symbolName)
|
||||
void add(Address addrKey, byte flags, int type, long[] values, byte[] bytes, String symbolName)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@@ -93,6 +95,7 @@ class RelocationDBAdapterV3 extends RelocationDBAdapter {
|
||||
}
|
||||
DBRecord newRec = SCHEMA.createRecord(rec.getKey());
|
||||
newRec.setLongValue(ADDR_COL, rec.getKey()); // key was encoded address
|
||||
newRec.setByteValue(FLAGS_COL, getFlags(Status.UNKNOWN, 0));
|
||||
newRec.setIntValue(TYPE_COL, rec.getIntValue(V3_TYPE_COL));
|
||||
newRec.setBinaryData(VALUE_COL, rec.getBinaryData(V3_VALUE_COL));
|
||||
newRec.setBinaryData(BYTES_COL, rec.getBinaryData(V3_BYTES_COL));
|
||||
|
||||
+6
-3
@@ -22,6 +22,7 @@ import ghidra.program.database.map.AddressKeyRecordIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
public class RelocationDBAdapterV4 extends RelocationDBAdapter {
|
||||
@@ -32,6 +33,7 @@ public class RelocationDBAdapterV4 extends RelocationDBAdapter {
|
||||
private final static int V4_BYTES_COL = 2;
|
||||
private final static int V4_SYMBOL_NAME_COL = 3;
|
||||
|
||||
/* Do not remove the following commented out schema! It shows the version 4 relocation table schema. */
|
||||
// final static Schema SCHEMA = new Schema(
|
||||
// RelocationDBAdapterV4.VERSION, "Address", new Field[] { IntField.INSTANCE,
|
||||
// BinaryField.INSTANCE, BinaryField.INSTANCE, StringField.INSTANCE },
|
||||
@@ -47,8 +49,8 @@ public class RelocationDBAdapterV4 extends RelocationDBAdapter {
|
||||
* @throws IOException if database IO error occurs
|
||||
* @throws VersionException throw if table schema is not V4
|
||||
*/
|
||||
RelocationDBAdapterV4(DBHandle handle, AddressMap addrMap) throws IOException,
|
||||
VersionException {
|
||||
RelocationDBAdapterV4(DBHandle handle, AddressMap addrMap)
|
||||
throws IOException, VersionException {
|
||||
this.addrMap = addrMap;
|
||||
relocTable = handle.getTable(TABLE_NAME);
|
||||
if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) {
|
||||
@@ -57,7 +59,7 @@ public class RelocationDBAdapterV4 extends RelocationDBAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
void add(Address addr, int type, long[] values, byte[] bytes, String symbolName)
|
||||
void add(Address addr, byte flags, int type, long[] values, byte[] bytes, String symbolName)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@@ -93,6 +95,7 @@ public class RelocationDBAdapterV4 extends RelocationDBAdapter {
|
||||
}
|
||||
DBRecord newRec = SCHEMA.createRecord(rec.getKey());
|
||||
newRec.setLongValue(ADDR_COL, rec.getKey()); // key was encoded address
|
||||
newRec.setByteValue(FLAGS_COL, getFlags(Status.UNKNOWN, 0));
|
||||
newRec.setIntValue(TYPE_COL, rec.getIntValue(V4_TYPE_COL));
|
||||
newRec.setBinaryData(VALUE_COL, rec.getBinaryData(V4_VALUE_COL)); // binary coded long[]
|
||||
newRec.setBinaryData(BYTES_COL, rec.getBinaryData(V4_BYTES_COL));
|
||||
|
||||
+48
-37
@@ -22,42 +22,47 @@ import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
public class RelocationDBAdapterV5 extends RelocationDBAdapter {
|
||||
final static int VERSION = 5;
|
||||
|
||||
final static int V5_ADDR_COL = 0; // indexed
|
||||
final static int V5_TYPE_COL = 1;
|
||||
final static int V5_VALUE_COL = 2;
|
||||
final static int V5_BYTES_COL = 3;
|
||||
final static int V5_SYMBOL_NAME_COL = 4;
|
||||
|
||||
/* Do not remove the following commented out schema! It shows the version 5 relocation table schema. */
|
||||
// final static Schema SCHEMA = new Schema(
|
||||
// RelocationDBAdapterV5.VERSION, "Index", new Field[] { LongField.INSTANCE, IntField.INSTANCE,
|
||||
// BinaryField.INSTANCE, BinaryField.INSTANCE, StringField.INSTANCE },
|
||||
// new String[] { "Address", "Type", "Values", "Bytes", "Symbol Name" });
|
||||
|
||||
private Table relocTable;
|
||||
private AddressMap addrMap;
|
||||
|
||||
RelocationDBAdapterV5(DBHandle handle, AddressMap addrMap, boolean create) throws IOException,
|
||||
VersionException {
|
||||
/**
|
||||
* Construct V5 read-only adapter
|
||||
* @param handle database adapter
|
||||
* @param addrMap address map for decode
|
||||
* @throws IOException if database IO error occurs
|
||||
* @throws VersionException throw if table schema is not V5
|
||||
*/
|
||||
RelocationDBAdapterV5(DBHandle handle, AddressMap addrMap)
|
||||
throws IOException, VersionException {
|
||||
this.addrMap = addrMap;
|
||||
if (create) {
|
||||
relocTable = handle.createTable(TABLE_NAME, SCHEMA, new int[] { ADDR_COL });
|
||||
}
|
||||
else {
|
||||
relocTable = handle.getTable(TABLE_NAME);
|
||||
if (relocTable == null) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
int version = relocTable.getSchema().getVersion();
|
||||
if (version != VERSION) {
|
||||
throw new VersionException(version < VERSION);
|
||||
}
|
||||
relocTable = handle.getTable(TABLE_NAME);
|
||||
if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) {
|
||||
throw new VersionException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void add(Address addr, int type, long[] values, byte[] bytes, String symbolName)
|
||||
void add(Address addr, byte flags, int type, long[] values, byte[] bytes, String symbolName)
|
||||
throws IOException {
|
||||
long key = relocTable.getKey();
|
||||
DBRecord r = SCHEMA.createRecord(key);
|
||||
r.setLongValue(ADDR_COL, addrMap.getKey(addr, true));
|
||||
r.setIntValue(TYPE_COL, type);
|
||||
r.setField(VALUE_COL, new BinaryCodedField(values));
|
||||
r.setBinaryData(BYTES_COL, bytes);
|
||||
r.setString(SYMBOL_NAME_COL, symbolName);
|
||||
relocTable.putRecord(r);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,35 +72,41 @@ public class RelocationDBAdapterV5 extends RelocationDBAdapter {
|
||||
|
||||
@Override
|
||||
RecordIterator iterator() throws IOException {
|
||||
return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
RecordIterator recIter =
|
||||
new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
ADDR_COL, addrMap, true));
|
||||
return new RecordIteratorAdapter(recIter);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator iterator(AddressSetView set) throws IOException {
|
||||
return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
RecordIterator recIter =
|
||||
new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
ADDR_COL, addrMap, set, true));
|
||||
return new RecordIteratorAdapter(recIter);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator iterator(Address start) throws IOException {
|
||||
return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
RecordIterator recIter =
|
||||
new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
ADDR_COL, addrMap, start, true));
|
||||
return new RecordIteratorAdapter(recIter);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord adaptRecord(DBRecord rec) {
|
||||
// my guess is that we don't need to do this until there is a version newer than us
|
||||
throw new UnsupportedOperationException("Don't know how to adapt to the new version");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add V5 relocation record to table.
|
||||
* @param rec relocation record
|
||||
* @throws IOException if database IO error occurs
|
||||
*/
|
||||
void add(DBRecord rec) throws IOException {
|
||||
relocTable.putRecord(rec);
|
||||
if (rec == null) {
|
||||
return null;
|
||||
}
|
||||
DBRecord newRec = SCHEMA.createRecord(rec.getKey());
|
||||
newRec.setLongValue(ADDR_COL, rec.getLongValue(V5_ADDR_COL));
|
||||
newRec.setByteValue(FLAGS_COL, getFlags(Status.UNKNOWN, 0));
|
||||
newRec.setIntValue(TYPE_COL, rec.getIntValue(V5_TYPE_COL));
|
||||
newRec.setBinaryData(VALUE_COL, rec.getBinaryData(V5_VALUE_COL)); // binary coded long[]
|
||||
newRec.setBinaryData(BYTES_COL, rec.getBinaryData(V5_BYTES_COL));
|
||||
newRec.setString(SYMBOL_NAME_COL, rec.getString(V5_SYMBOL_NAME_COL));
|
||||
return newRec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.database.reloc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
/**
|
||||
* Relocation Adapter (v6) introduced a stored status and length value. The byte-length value
|
||||
* is only stored/used when stored bytes are not used and the original bytes are obtained from
|
||||
* the underlying {@link FileBytes} via associated {@link Memory}. Older program's may
|
||||
* have a stored bytes array but is unneccessary when original FileBytes are available.
|
||||
* <br>
|
||||
* During the transition of older relocation records we are unable to determine a proper status
|
||||
* without comparing current memory to the original bytes. It may also be neccessary to reconcile
|
||||
* overlapping relocations when the stored bytes value is null to obtain a valid length. This
|
||||
* transition is too complicated for a low-level record translation so it must be deferred to
|
||||
* a higher-level program upgrade (see {@link ProgramDB}). This also holds true for establishing
|
||||
* a reasonable status for existing relocation records. During the initial record migration a
|
||||
* status of {@link Status#UNKNOWN} and default length will be used. After the program is
|
||||
* ready another high-level upgrade, based on Program version, will then attempt to refine these
|
||||
* records further.
|
||||
*/
|
||||
public class RelocationDBAdapterV6 extends RelocationDBAdapter {
|
||||
|
||||
final static int VERSION = 6;
|
||||
private Table relocTable;
|
||||
private AddressMap addrMap;
|
||||
|
||||
/**
|
||||
* Construct V6 relocation adapter
|
||||
* @param handle database adapter
|
||||
* @param addrMap address map for decode
|
||||
* @param create true if new table should be created, else open existing table
|
||||
* @throws IOException if database IO error occurs
|
||||
* @throws VersionException throw if table schema is not V6
|
||||
*/
|
||||
RelocationDBAdapterV6(DBHandle handle, AddressMap addrMap, boolean create) throws IOException,
|
||||
VersionException {
|
||||
this.addrMap = addrMap;
|
||||
if (create) {
|
||||
relocTable = handle.createTable(TABLE_NAME, SCHEMA, new int[] { ADDR_COL });
|
||||
}
|
||||
else {
|
||||
relocTable = handle.getTable(TABLE_NAME);
|
||||
if (relocTable == null) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
int version = relocTable.getSchema().getVersion();
|
||||
if (version != VERSION) {
|
||||
throw new VersionException(version < VERSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void add(Address addr, byte flags, int type, long[] values, byte[] bytes, String symbolName)
|
||||
throws IOException {
|
||||
long key = relocTable.getKey();
|
||||
DBRecord r = SCHEMA.createRecord(key);
|
||||
r.setLongValue(ADDR_COL, addrMap.getKey(addr, true));
|
||||
r.setByteValue(FLAGS_COL, flags);
|
||||
r.setIntValue(TYPE_COL, type);
|
||||
r.setField(VALUE_COL, new BinaryCodedField(values));
|
||||
r.setBinaryData(BYTES_COL, bytes);
|
||||
r.setString(SYMBOL_NAME_COL, symbolName);
|
||||
relocTable.putRecord(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
int getRecordCount() {
|
||||
return relocTable.getRecordCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator iterator() throws IOException {
|
||||
return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
ADDR_COL, addrMap, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator iterator(AddressSetView set) throws IOException {
|
||||
return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
ADDR_COL, addrMap, set, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator iterator(Address start) throws IOException {
|
||||
return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable,
|
||||
ADDR_COL, addrMap, start, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord adaptRecord(DBRecord rec) {
|
||||
// my guess is that we don't need to do this until there is a version newer than us
|
||||
throw new UnsupportedOperationException("Don't know how to adapt to the new version");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update relocation table record.
|
||||
* @param rec relocation record
|
||||
* @throws IOException if database IO error occurs
|
||||
*/
|
||||
void put(DBRecord rec) throws IOException {
|
||||
relocTable.putRecord(rec);
|
||||
}
|
||||
|
||||
}
|
||||
+83
-27
@@ -24,12 +24,12 @@ import ghidra.program.database.ManagerDB;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.database.mem.AddressSourceInfo;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlockSourceInfo;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
@@ -84,39 +84,91 @@ public class RelocationManager implements RelocationTable, ManagerDB {
|
||||
@Override
|
||||
public void programReady(int openMode, int currentRevision, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
// Nothing to do
|
||||
|
||||
if (currentRevision < ProgramDB.RELOCATION_STATUS_ADDED_VERSION) {
|
||||
RelocationDBAdapter.preV6DataMigrationUpgrade(adapter, program, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getOriginalBytes(Address addr, byte[] bytes) throws IOException {
|
||||
if (bytes != null) {
|
||||
return bytes;
|
||||
}
|
||||
int byteCount = program.getDefaultPointerSize() > 4 ? 8 : 4;
|
||||
/**
|
||||
* Get default byte length when unknown
|
||||
* @param program program containing relocation
|
||||
* @return default byte length
|
||||
*/
|
||||
static int getDefaultOriginalByteLength(Program program) {
|
||||
return program.getDefaultPointerSize() > 4 ? 8 : 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the specified number of original file bytes for the specified address. Any offsets
|
||||
* not backed by file bytes will have a 0-byte value.
|
||||
* @param memory program memory
|
||||
* @param addr memory address
|
||||
* @param byteCount number of original file bytes to read
|
||||
* @return byte array of length byteCount
|
||||
* @throws IOException if an IO error occurs
|
||||
*/
|
||||
static byte[] getOriginalBytes(Memory memory, Address addr, int byteCount) throws IOException {
|
||||
byte[] originalBytes = new byte[byteCount];
|
||||
AddressSourceInfo addressSourceInfo = program.getMemory().getAddressSourceInfo(addr);
|
||||
if (addressSourceInfo == null) {
|
||||
return null;
|
||||
}
|
||||
MemoryBlockSourceInfo memoryBlockSourceInfo = addressSourceInfo.getMemoryBlockSourceInfo();
|
||||
Optional<FileBytes> optional = memoryBlockSourceInfo.getFileBytes();
|
||||
if (!optional.isEmpty()) {
|
||||
FileBytes fileBytes = optional.get();
|
||||
long fileBytesOffset = addressSourceInfo.getFileOffset();
|
||||
long offsetIntoSourceRange =
|
||||
fileBytesOffset - memoryBlockSourceInfo.getFileBytesOffset();
|
||||
long available = memoryBlockSourceInfo.getLength() - offsetIntoSourceRange;
|
||||
int readSize = (int) Math.min(available, byteCount);
|
||||
fileBytes.getOriginalBytes(fileBytesOffset, originalBytes, 0, readSize);
|
||||
// must get one byte at a time due to the possibility of byte-mapped memory use
|
||||
for (int i = 0; i < byteCount; i++) {
|
||||
if (i != 0) {
|
||||
addr = addr.next();
|
||||
}
|
||||
if (addr == null) {
|
||||
break;
|
||||
}
|
||||
AddressSourceInfo addressSourceInfo = memory.getAddressSourceInfo(addr);
|
||||
if (addressSourceInfo == null) {
|
||||
return originalBytes;
|
||||
}
|
||||
originalBytes[i] = addressSourceInfo.getOriginalValue();
|
||||
}
|
||||
return originalBytes;
|
||||
}
|
||||
|
||||
private byte[] getOriginalBytes(Address addr, Status status, byte[] bytes, int defaultLength)
|
||||
throws IOException {
|
||||
if (bytes != null || !status.hasBytes()) {
|
||||
return bytes;
|
||||
}
|
||||
int byteCount = defaultLength;
|
||||
if (defaultLength <= 0) {
|
||||
byteCount = getDefaultOriginalByteLength(program);
|
||||
}
|
||||
return getOriginalBytes(program.getMemory(), addr, byteCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Relocation add(Address addr, int type, long[] values, byte[] bytes, String symbolName) {
|
||||
public Relocation add(Address addr, Status status, int type, long[] values, byte[] bytes,
|
||||
String symbolName) {
|
||||
lock.acquire();
|
||||
try {
|
||||
adapter.add(addr, type, values, bytes, symbolName);
|
||||
return new Relocation(addr, type, values, getOriginalBytes(addr, bytes), symbolName);
|
||||
byte flags = RelocationDBAdapter.getFlags(status, 0);
|
||||
adapter.add(addr, flags, type, values, bytes, symbolName);
|
||||
return new Relocation(addr, status, type, values,
|
||||
getOriginalBytes(addr, status, bytes, 0),
|
||||
symbolName);
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Relocation add(Address addr, Status status, int type, long[] values, int byteLength,
|
||||
String symbolName) {
|
||||
lock.acquire();
|
||||
try {
|
||||
byte flags = RelocationDBAdapter.getFlags(status, byteLength);
|
||||
adapter.add(addr, flags, type, values, null, symbolName);
|
||||
return new Relocation(addr, status, type, values,
|
||||
getOriginalBytes(addr, status, null, byteLength),
|
||||
symbolName);
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
@@ -178,11 +230,15 @@ public class RelocationManager implements RelocationTable, ManagerDB {
|
||||
|
||||
private Relocation getRelocation(DBRecord rec) throws IOException {
|
||||
Address addr = addrMap.decodeAddress(rec.getLongValue(RelocationDBAdapter.ADDR_COL));
|
||||
byte flags = rec.getByteValue(RelocationDBAdapter.FLAGS_COL);
|
||||
Status status = RelocationDBAdapter.getStatus(flags);
|
||||
int length = RelocationDBAdapter.getByteLength(flags);
|
||||
BinaryCodedField valuesField =
|
||||
new BinaryCodedField((BinaryField) rec.getFieldValue(RelocationDBAdapter.VALUE_COL));
|
||||
byte[] originalBytes =
|
||||
getOriginalBytes(addr, rec.getBinaryData(RelocationDBAdapter.BYTES_COL));
|
||||
return new Relocation(addr, rec.getIntValue(RelocationDBAdapter.TYPE_COL),
|
||||
getOriginalBytes(addr, status, rec.getBinaryData(RelocationDBAdapter.BYTES_COL),
|
||||
length);
|
||||
return new Relocation(addr, status, rec.getIntValue(RelocationDBAdapter.TYPE_COL),
|
||||
valuesField.getLongArray(),
|
||||
originalBytes, rec.getString(RelocationDBAdapter.SYMBOL_NAME_COL));
|
||||
}
|
||||
|
||||
+102
-1
@@ -22,7 +22,96 @@ import ghidra.program.model.address.Address;
|
||||
* program relocation.
|
||||
*/
|
||||
public class Relocation {
|
||||
|
||||
/**
|
||||
* Relocation status.
|
||||
*/
|
||||
public enum Status {
|
||||
|
||||
// NOTE: associated values must not change since they are retained within the database
|
||||
|
||||
/**
|
||||
* Relocation status is unknown and is assumed to have modified memory bytes.
|
||||
* This status is intended for relocation data upgrades when actual status can not
|
||||
* be determined.
|
||||
*/
|
||||
UNKNOWN(0, true),
|
||||
|
||||
/**
|
||||
* Relocation has be intentionally skipped and should not be treated as a failure.
|
||||
*/
|
||||
SKIPPED(1, false),
|
||||
|
||||
/**
|
||||
* Relocation type is not supported at the time relocations were applied.
|
||||
*/
|
||||
UNSUPPORTED(2, false),
|
||||
|
||||
/**
|
||||
* A supported relocation fail to apply properly. This may be the result of an unexpected
|
||||
* or unsupported condition which prevented its application.
|
||||
*/
|
||||
FAILURE(3, false),
|
||||
|
||||
/**
|
||||
* Relocation was processed successfully although relies on a subsequent relocation to
|
||||
* affect memory.
|
||||
*/
|
||||
PARTIAL(4, false),
|
||||
|
||||
/**
|
||||
* Relocation was applied successfully and resulted in the modification of memory bytes.
|
||||
*/
|
||||
APPLIED(5, true),
|
||||
|
||||
/**
|
||||
* Loaded memory has been altered during the load process and may, or may not, be directly
|
||||
* associated with a standard relocation type.
|
||||
*/
|
||||
APPLIED_OTHER(6, true);
|
||||
|
||||
private int value;
|
||||
private boolean hasBytes;
|
||||
|
||||
private Status(int value, boolean hasBytes) {
|
||||
this.value = value;
|
||||
this.hasBytes = hasBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if relocation reflects original bytes that may have been modified,
|
||||
* else false.
|
||||
*/
|
||||
public boolean hasBytes() {
|
||||
return hasBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage value associated
|
||||
* @return storage value associated with status
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Status which corresponds to the specified value.
|
||||
* @param value status value
|
||||
* @return status enum
|
||||
*/
|
||||
public static Status getStatus(int value) {
|
||||
for (Status s : values()) {
|
||||
if (s.value == value) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"Undefined Status value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
private Address addr;
|
||||
private Status status;
|
||||
private int type;
|
||||
private long[] values;
|
||||
private byte[] bytes;
|
||||
@@ -32,14 +121,17 @@ public class Relocation {
|
||||
* Constructs a new relocation.
|
||||
*
|
||||
* @param addr the address where the relocation is required
|
||||
* @param status relocation status
|
||||
* @param type the type of relocation to perform
|
||||
* @param values the values needed when performing the relocation. Definition of values is
|
||||
* specific to loader used and relocation type.
|
||||
* @param bytes original instruction bytes affected by relocation
|
||||
* @param symbolName the name of the symbol being relocated
|
||||
*/
|
||||
public Relocation(Address addr, int type, long[] values, byte[] bytes, String symbolName) {
|
||||
public Relocation(Address addr, Status status, int type, long[] values, byte[] bytes,
|
||||
String symbolName) {
|
||||
this.addr = addr;
|
||||
this.status = status;
|
||||
this.type = type;
|
||||
this.values = values;
|
||||
this.bytes = bytes;
|
||||
@@ -55,6 +147,15 @@ public class Relocation {
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relocation's application status within the program.
|
||||
*
|
||||
* @return relocation's application status within the program.
|
||||
*/
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the relocation to perform.
|
||||
*
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.reloc;
|
||||
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
|
||||
/**
|
||||
* {@link RelocationResult} provides the status and byte-length of a processed relocation during
|
||||
* the {@link Program} load process. Intended to be used internally by a relocation handler.
|
||||
* A positive byte-length is only required for a status of {@link Status#APPLIED} or
|
||||
* {@link Status#APPLIED_OTHER}. Use if {@link Status#UNKNOWN} should be avoided and is intended
|
||||
* for relocation data upgrades when actual status can not be determined.
|
||||
* <br>
|
||||
* Singleton instances are provided for relocations which did not directly results in original
|
||||
* loaded memory modification.
|
||||
*
|
||||
* @param status the relocation status
|
||||
* @param byteLength the number of original bytes modified at relocation offset if successfully
|
||||
* applied and memory bytes were modified.
|
||||
*/
|
||||
public record RelocationResult(Status status, int byteLength) {
|
||||
|
||||
/**
|
||||
* See {@link Status#FAILURE}
|
||||
*/
|
||||
public static final RelocationResult FAILURE = new RelocationResult(Status.FAILURE, 0);
|
||||
|
||||
/**
|
||||
* See {@link Status#UNSUPPORTED}
|
||||
*/
|
||||
public static final RelocationResult UNSUPPORTED = new RelocationResult(Status.UNSUPPORTED, 0);
|
||||
|
||||
/**
|
||||
* See {@link Status#SKIPPED}
|
||||
*/
|
||||
public static final RelocationResult SKIPPED = new RelocationResult(Status.SKIPPED, 0);
|
||||
|
||||
/**
|
||||
* See {@link Status#PARTIAL}
|
||||
*/
|
||||
public static final RelocationResult PARTIAL = new RelocationResult(Status.PARTIAL, 0);
|
||||
|
||||
}
|
||||
+30
-8
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
|
||||
/**
|
||||
* An interface for storing the relocations defined in a program.
|
||||
@@ -32,19 +33,40 @@ public interface RelocationTable {
|
||||
public static final String RELOCATABLE_PROP_NAME = "Relocatable";
|
||||
|
||||
/**
|
||||
* Creates and adds a new relocation with the specified
|
||||
* address, type, and value.
|
||||
* Adds a new relocation entry when the original bytes being replaced are to be specified.
|
||||
*
|
||||
* @param addr the address where the relocation is required
|
||||
* @param addr the memory address where the relocation is required
|
||||
* @param status relocation status (use {@link Status#UNKNOWN} if not known).
|
||||
* @param type the type of relocation to perform
|
||||
* @param values the values needed when performing the relocation. Definition of values is
|
||||
* specific to loader used and relocation type.
|
||||
* @param bytes original instruction bytes affected by relocation. A null value should be
|
||||
* passed to rely on original underlying {@link FileBytes}.
|
||||
* @param values relocation-specific values which may be useful in diagnosing relocation;
|
||||
* may be null.
|
||||
* @param bytes original memory bytes affected by relocation. A null value may be
|
||||
* passed but this case is deprecated (see {@link #add(Address, Status, int, long[], int, String)}.
|
||||
* If null is specified and {@link Status#hasBytes()} is true a default number of original
|
||||
* bytes will be assumed and obtained from the underlying memory {@link FileBytes} if possible.
|
||||
* @param symbolName the name of the symbol being relocated; may be null
|
||||
* @return the newly added relocation object
|
||||
*/
|
||||
public Relocation add(Address addr, int type, long[] values, byte[] bytes, String symbolName);
|
||||
public Relocation add(Address addr, Status status, int type, long[] values, byte[] bytes,
|
||||
String symbolName);
|
||||
|
||||
/**
|
||||
* Adds a new relocation entry when the original bytes being replaced should be determined
|
||||
* from the underlying {@link FileBytes}.
|
||||
*
|
||||
* @param addr the memory address where the relocation is required
|
||||
* @param status relocation status (use {@link Status#UNKNOWN} if not known).
|
||||
* @param type the type of relocation to perform
|
||||
* @param values relocation-specific values which may be useful in diagnosing relocation;
|
||||
* may be null.
|
||||
* @param byteLength the number of bytes affected by this relocation. This value is only
|
||||
* used with a status of {@link Status#UNKNOWN}, {@link Status#APPLIED} or
|
||||
* {@link Status#APPLIED_OTHER}. Valid range is 1..8 bytes.
|
||||
* @param symbolName the name of the symbol being relocated; may be null
|
||||
* @return the newly added relocation object
|
||||
*/
|
||||
public Relocation add(Address addr, Status status, int type, long[] values, int byteLength,
|
||||
String symbolName);
|
||||
|
||||
/**
|
||||
* Returns the ordered list of relocations which have been defined for the specified address.
|
||||
|
||||
+27
-11
@@ -22,6 +22,8 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
@@ -37,12 +39,13 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
public RelocationResult relocate(ElfRelocationContext elfRelocationContext,
|
||||
ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
ElfHeader elf = elfRelocationContext.getElfHeader();
|
||||
if (elf.e_machine() != ElfConstants.EM_AARCH64) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
@@ -50,7 +53,7 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
int type = relocation.getType();
|
||||
if (type == AARCH64_ElfRelocationConstants.R_AARCH64_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
||||
@@ -72,6 +75,8 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
long symbolValue = elfRelocationContext.getSymbolValue(sym);
|
||||
long newValue = 0;
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (type) {
|
||||
// .xword: (S+A)
|
||||
case AARCH64_ElfRelocationConstants.R_AARCH64_ABS64: {
|
||||
@@ -82,6 +87,7 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
|
||||
applyComponentOffsetPointer(program, relocationAddress, addend);
|
||||
}
|
||||
byteLength = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -99,6 +105,7 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
case AARCH64_ElfRelocationConstants.R_AARCH64_P32_ABS16: {
|
||||
newValue = (symbolValue + addend);
|
||||
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
|
||||
byteLength = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -107,6 +114,7 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
newValue = (symbolValue + addend);
|
||||
newValue -= (offset); // PC relative
|
||||
memory.setLong(relocationAddress, newValue);
|
||||
byteLength = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -125,6 +133,7 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
newValue = (symbolValue + addend);
|
||||
newValue -= (offset); // PC relative
|
||||
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
|
||||
byteLength = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -238,7 +247,7 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
addend = getValue(memory, relocationAddress, is64bit);
|
||||
}
|
||||
newValue = symbolValue + addend;
|
||||
setValue(memory, relocationAddress, newValue, is64bit);
|
||||
byteLength = setValue(memory, relocationAddress, newValue, is64bit);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -251,11 +260,13 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
// GOT entry bytes if it refers to .plt block
|
||||
Address symAddress = elfRelocationContext.getSymbolAddress(sym);
|
||||
MemoryBlock block = memory.getBlock(symAddress);
|
||||
// TODO: jump slots are always in GOT - not sure why PLT check is done
|
||||
boolean isPltSym = block != null && block.getName().startsWith(".plt");
|
||||
boolean isExternalSym =
|
||||
block != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName());
|
||||
if (!isPltSym) {
|
||||
setValue(memory, relocationAddress, symAddress.getOffset(), is64bit);
|
||||
byteLength =
|
||||
setValue(memory, relocationAddress, symAddress.getOffset(), is64bit);
|
||||
}
|
||||
if ((isPltSym || isExternalSym) && !StringUtils.isBlank(symbolName)) {
|
||||
Function extFunction =
|
||||
@@ -265,7 +276,7 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
markAsError(program, relocationAddress, "R_AARCH64_JUMP_SLOT", symbolName,
|
||||
"Failed to create R_AARCH64_JUMP_SLOT external function",
|
||||
elfRelocationContext.getLog());
|
||||
return;
|
||||
// relocation already applied above
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -278,7 +289,7 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
addend = getValue(memory, relocationAddress, is64bit);
|
||||
}
|
||||
newValue = elfRelocationContext.getImageBaseWordAdjustmentOffset() + addend;
|
||||
setValue(memory, relocationAddress, newValue, is64bit);
|
||||
byteLength = setValue(memory, relocationAddress, newValue, is64bit);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -286,14 +297,16 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
case AARCH64_ElfRelocationConstants.R_AARCH64_COPY: {
|
||||
markAsWarning(program, relocationAddress, "R_AARCH64_COPY", symbolName, symbolIndex,
|
||||
"Runtime copy not supported", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
|
||||
default: {
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,15 +315,18 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
* @param addr address to set new value
|
||||
* @param value value
|
||||
* @param is64bit true if value is 64, false if 32bit
|
||||
* return value byte-length
|
||||
* @throws MemoryAccessException on set of value
|
||||
*/
|
||||
private void setValue(Memory memory, Address addr, long value, boolean is64bit)
|
||||
private int setValue(Memory memory, Address addr, long value, boolean is64bit)
|
||||
throws MemoryAccessException {
|
||||
if (is64bit) {
|
||||
memory.setLong(addr, value);
|
||||
} else {
|
||||
memory.setInt(addr, (int) value);
|
||||
return 8;
|
||||
}
|
||||
|
||||
memory.setInt(addr, (int) value);
|
||||
return 4;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+16
-12
@@ -17,11 +17,13 @@ package ghidra.app.util.bin.format.macho.relocation;
|
||||
|
||||
import static ghidra.app.util.bin.format.macho.relocation.AARCH64_MachoRelocationConstants.*;
|
||||
|
||||
import ghidra.app.util.bin.format.RelocationException;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.util.Conv;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
/**
|
||||
* A {@link MachoRelocationHandler} for AARCH64
|
||||
@@ -42,11 +44,11 @@ public class AARCH64_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(MachoRelocation relocation)
|
||||
throws MemoryAccessException, NotFoundException {
|
||||
public RelocationResult relocate(MachoRelocation relocation)
|
||||
throws MemoryAccessException, RelocationException {
|
||||
|
||||
if (!relocation.requiresRelocation()) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
RelocationInfo relocationInfo = relocation.getRelocationInfo();
|
||||
@@ -69,21 +71,22 @@ public class AARCH64_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
}
|
||||
long orig = read(relocation);
|
||||
|
||||
int byteLength;
|
||||
switch (relocationInfo.getType()) {
|
||||
case ARM64_RELOC_UNSIGNED:
|
||||
case ARM64_RELOC_POINTER_TO_GOT: {
|
||||
long addend = orig;
|
||||
long value = targetAddr.getOffset() + addend;
|
||||
write(relocation, value);
|
||||
byteLength = write(relocation, value);
|
||||
break;
|
||||
}
|
||||
case ARM64_RELOC_SUBTRACTOR: {
|
||||
Address targetAddrExtra = relocation.getTargetAddressExtra();
|
||||
if (orig > 0) {
|
||||
write(relocation, targetAddrExtra.add(orig).subtract(targetAddr));
|
||||
byteLength = write(relocation, targetAddrExtra.add(orig).subtract(targetAddr));
|
||||
}
|
||||
else {
|
||||
write(relocation, targetAddr.add(orig).subtract(targetAddrExtra));
|
||||
byteLength = write(relocation, targetAddr.add(orig).subtract(targetAddrExtra));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -91,7 +94,7 @@ public class AARCH64_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
long addend = orig & 0x3ffffff;
|
||||
long value = (targetAddr.subtract(relocAddr) >> 2) + addend;
|
||||
long instr = orig | (value & 0x3ffffff);
|
||||
write(relocation, instr);
|
||||
byteLength = write(relocation, instr);
|
||||
break;
|
||||
}
|
||||
case ARM64_RELOC_PAGE21:
|
||||
@@ -106,7 +109,7 @@ public class AARCH64_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
long value = ((pageTarget - pageReloc) >> 12) & 0x1fffff;
|
||||
long instr =
|
||||
(orig & 0x9f00001f) | ((value << 3) & 0x7ffffe0) | ((value & 0x3) << 29);
|
||||
write(relocation, instr);
|
||||
byteLength = write(relocation, instr);
|
||||
break;
|
||||
}
|
||||
case ARM64_RELOC_PAGEOFF12:
|
||||
@@ -126,13 +129,13 @@ public class AARCH64_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
long value = (targetAddr.getOffset() + addend) & 0xfff;
|
||||
instr = orig | (value << 10);
|
||||
}
|
||||
write(relocation, instr);
|
||||
byteLength = write(relocation, instr);
|
||||
break;
|
||||
}
|
||||
case ARM64_RELOC_AUTHENTICATED_POINTER: {
|
||||
long addend = orig & Conv.INT_MASK;
|
||||
long value = targetAddr.getOffset() + addend;
|
||||
write(relocation, value);
|
||||
byteLength = write(relocation, value);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -140,8 +143,9 @@ public class AARCH64_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12: // not seen yet
|
||||
case ARM64_RELOC_ADDEND: // should never see on its own here
|
||||
default:
|
||||
throw new NotFoundException("Unimplemented relocation");
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+17
-6
@@ -22,6 +22,8 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
@@ -43,13 +45,13 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext context, ElfRelocation relocation,
|
||||
public RelocationResult relocate(ElfRelocationContext context, ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
ElfHeader elf = context.getElfHeader();
|
||||
if (elf.e_machine() != ElfConstants.EM_ARM ||
|
||||
!(context instanceof ARM_ElfRelocationContext)) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
ARM_ElfRelocationContext elfRelocationContext = (ARM_ElfRelocationContext) context;
|
||||
@@ -62,7 +64,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
int type = relocation.getType();
|
||||
if (type == ARM_ElfRelocationConstants.R_ARM_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
||||
@@ -80,6 +82,8 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
int newValue = 0;
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (type) {
|
||||
case ARM_ElfRelocationConstants.R_ARM_PC24: { // Target class: ARM Instruction
|
||||
int oldValue = memory.getInt(relocationAddress, instructionBigEndian);
|
||||
@@ -154,6 +158,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
case ARM_ElfRelocationConstants.R_ARM_ABS16: { // Target class: Data
|
||||
short sValue = (short) (symbolValue + addend);
|
||||
memory.setShort(relocationAddress, sValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
}
|
||||
case ARM_ElfRelocationConstants.R_ARM_ABS12: { // Target class: ARM Instruction
|
||||
@@ -171,6 +176,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
case ARM_ElfRelocationConstants.R_ARM_ABS_8: { // Target class: Data
|
||||
byte bValue = (byte) (symbolValue + addend);
|
||||
memory.setByte(relocationAddress, bValue);
|
||||
byteLength = 1;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
@@ -221,6 +227,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
newValue = newValue >> 1;
|
||||
short sValue = (short) ((oldValue & 0xff00) | (newValue & 0x00ff));
|
||||
memory.setShort(relocationAddress, sValue, instructionBigEndian);
|
||||
byteLength = 2;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
@@ -270,6 +277,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
// GOT entry bytes if it refers to .plt block
|
||||
Address symAddress = elfRelocationContext.getSymbolAddress(sym);
|
||||
MemoryBlock block = memory.getBlock(symAddress);
|
||||
// TODO: jump slots are always in GOT - not sure why PLT check is done
|
||||
boolean isPltSym = block != null && block.getName().startsWith(".plt");
|
||||
boolean isExternalSym =
|
||||
block != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName());
|
||||
@@ -284,7 +292,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
markAsError(program, relocationAddress, "R_ARM_JUMP_SLOT", symbolName,
|
||||
"Failed to create R_ARM_JUMP_SLOT external function",
|
||||
elfRelocationContext.getLog());
|
||||
return;
|
||||
// relocation already applied above
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -592,6 +600,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
newValue -= (offset + elfRelocationContext.getPcBias(true)); // PC relative
|
||||
newValue = (oldValue & 0x0000f800) | ((newValue >> 1) & 0x000007ff);
|
||||
memory.setShort(relocationAddress, (short) newValue, instructionBigEndian);
|
||||
byteLength = 2;
|
||||
break;
|
||||
}
|
||||
case ARM_ElfRelocationConstants.R_ARM_THM_JUMP8: {
|
||||
@@ -603,6 +612,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
newValue -= (offset + elfRelocationContext.getPcBias(true)); // PC relative
|
||||
newValue = (oldValue & 0x0000ff00) | ((newValue >> 1) & 0x000000ff);
|
||||
memory.setShort(relocationAddress, (short) newValue, instructionBigEndian);
|
||||
byteLength = 2;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
@@ -689,15 +699,16 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
case ARM_ElfRelocationConstants.R_ARM_COPY: {
|
||||
markAsWarning(program, relocationAddress, "R_ARM_COPY", symbolName, symbolIndex,
|
||||
"Runtime copy not supported", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
|
||||
default: {
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
private boolean isThumb(ElfSymbol symbol) {
|
||||
|
||||
+12
-8
@@ -17,10 +17,12 @@ package ghidra.app.util.bin.format.macho.relocation;
|
||||
|
||||
import static ghidra.app.util.bin.format.macho.relocation.ARM_MachoRelocationConstants.*;
|
||||
|
||||
import ghidra.app.util.bin.format.RelocationException;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
|
||||
/**
|
||||
* A {@link MachoRelocationHandler} for ARM
|
||||
@@ -43,24 +45,25 @@ public class ARM_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(MachoRelocation relocation)
|
||||
throws MemoryAccessException, NotFoundException {
|
||||
public RelocationResult relocate(MachoRelocation relocation)
|
||||
throws MemoryAccessException, RelocationException {
|
||||
|
||||
if (!relocation.requiresRelocation()) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
RelocationInfo relocationInfo = relocation.getRelocationInfo();
|
||||
Address targetAddr = relocation.getTargetAddress();
|
||||
long orig = read(relocation);
|
||||
|
||||
int byteLength;
|
||||
switch (relocationInfo.getType()) {
|
||||
case ARM_RELOC_VANILLA:
|
||||
if (!relocationInfo.isPcRelocated()) {
|
||||
write(relocation, targetAddr.getOffset());
|
||||
byteLength = write(relocation, targetAddr.getOffset());
|
||||
}
|
||||
else {
|
||||
throw new NotFoundException("Unimplemented relocation");
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
break;
|
||||
case ARM_THUMB_RELOC_BR22: {
|
||||
@@ -86,7 +89,7 @@ public class ARM_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
imm11 = (value >> 1) & 0x7ff;
|
||||
long instr = orig & (blx ? 0xc000f800 : 0xd000f800);
|
||||
instr |= (j1 << 29) | (j2 << 27) | (imm11 << 16) | (s << 10) | imm10;
|
||||
write(relocation, instr);
|
||||
byteLength = write(relocation, instr);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -99,7 +102,8 @@ public class ARM_MachoRelocationHandler extends MachoRelocationHandler {
|
||||
case ARM_RELOC_HALF: // relocation not required (scattered)
|
||||
case ARM_RELOC_HALF_SECTDIFF: // relocation not required (scattered)
|
||||
default:
|
||||
throw new NotFoundException("Unimplemented relocation");
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-4
@@ -24,6 +24,8 @@ import ghidra.program.model.listing.Listing;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
@@ -35,7 +37,8 @@ public class AVR32_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
public RelocationResult relocate(ElfRelocationContext elfRelocationContext,
|
||||
ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
@@ -57,11 +60,13 @@ public class AVR32_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
int oldValue = memory.getInt(relocationAddress);
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
if (elf.e_machine() == ElfConstants.EM_AVR32) {
|
||||
int newValueShiftToAligntoUpper = 0;
|
||||
switch (type) {
|
||||
case AVR32_ElfRelocationConstants.R_AVR32_NONE:
|
||||
break;
|
||||
return RelocationResult.SKIPPED;
|
||||
case AVR32_ElfRelocationConstants.R_AVR32_32:
|
||||
int newValue = (((int) symbolValue + (int) addend) & 0xffffffff);
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
@@ -188,7 +193,7 @@ public class AVR32_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
System.out.println(" HANDLED AVR relocation: R_AVR32_ALIGN at "+relocationAddress + ", New = " + newValue);
|
||||
}*/
|
||||
//System.out.println(" HANDLED AVR relocation: R_AVR32_ALIGN at "+relocationAddress + ", OldValue = " + Integer.toHexString(oldValue));
|
||||
break;
|
||||
return RelocationResult.SKIPPED;
|
||||
|
||||
//TODO: THE FOLLOWING:
|
||||
/*case AVR32_ElfRelocationConstants.R_AVR32_16_CP:
|
||||
@@ -316,9 +321,10 @@ public class AVR32_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex,
|
||||
elfRelocationContext.getSymbolName(symbolIndex),
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+26
-14
@@ -20,6 +20,8 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
@@ -30,7 +32,8 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
public RelocationResult relocate(ElfRelocationContext elfRelocationContext,
|
||||
ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
@@ -57,14 +60,15 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
int oldValue = memory.getShort(relocationAddress);
|
||||
|
||||
if (elf.e_machine() != ElfConstants.EM_AVR) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
int newValue = 0;
|
||||
int byteLength = 2; // most relocations affect 2-bytes (change if different)
|
||||
|
||||
switch (type) {
|
||||
case AVR8_ElfRelocationConstants.R_AVR_NONE:
|
||||
break;
|
||||
return RelocationResult.SKIPPED;
|
||||
|
||||
case AVR8_ElfRelocationConstants.R_AVR_32:
|
||||
newValue = (((int) symbolValue + (int) addend) & 0xffffffff);
|
||||
@@ -78,12 +82,12 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
if (newValue > ((1 << 7) - 1) || (newValue < -(1 << 7))) {
|
||||
markAsError(program, relocationAddress, type, symbolName, "relocation overflow",
|
||||
elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue = (oldValue & 0xfc07) | (((newValue >> 1) << 3) & 0x3f8);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
@@ -96,7 +100,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue >>= 1;
|
||||
|
||||
@@ -168,7 +172,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue >>= 1;
|
||||
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
|
||||
@@ -180,7 +184,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue >>= 1;
|
||||
newValue = (newValue >> 8) & 0xff;
|
||||
@@ -193,7 +197,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue >>= 1;
|
||||
newValue = (newValue >> 16) & 0xff;
|
||||
@@ -207,7 +211,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue >>= 1;
|
||||
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
|
||||
@@ -220,7 +224,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue >>= 1;
|
||||
newValue = (newValue >> 8) & 0xff;
|
||||
@@ -234,7 +238,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue >>= 1;
|
||||
newValue = (newValue >> 16) & 0xff;
|
||||
@@ -248,7 +252,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 1) == 1) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
newValue >>= 1;
|
||||
|
||||
@@ -256,6 +260,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
oldValue | ((newValue & 0x10000) | ((newValue << 3) & 0x1f00000)) >> 16;
|
||||
memory.setShort(relocationAddress, (short) (hiValue & 0xffff));
|
||||
memory.setShort(relocationAddress.add(2), (short) (newValue & 0xffff));
|
||||
byteLength = 4;
|
||||
break;
|
||||
|
||||
case AVR8_ElfRelocationConstants.R_AVR_LDI: /* data/eeprom */
|
||||
@@ -264,6 +269,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 0xffff) > 255) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
// continue to apply
|
||||
}
|
||||
|
||||
newValue = (newValue >> 8) & 0xff;
|
||||
@@ -277,6 +283,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if (((newValue & 0xffff) > 63) || (newValue < 0)) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
// continue to apply
|
||||
}
|
||||
|
||||
newValue = (oldValue & 0xd3f8) | (newValue & 7) | ((newValue & (3 << 3)) << 7) |
|
||||
@@ -290,6 +297,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if (((newValue & 0xffff) > 63) || (newValue < 0)) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
// continue to apply
|
||||
}
|
||||
|
||||
newValue = (oldValue & 0xff30) | (newValue & 0xF) | ((newValue & 0x30) << 2);
|
||||
@@ -309,6 +317,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if (((newValue & 0xffff) < 0x40) || (newValue & 0xFFFF) > 0xbf) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
// continue to apply
|
||||
}
|
||||
|
||||
newValue = newValue & 0x7f;
|
||||
@@ -322,6 +331,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 0xffff) > 0x3f) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
// continue to apply
|
||||
}
|
||||
|
||||
newValue = (oldValue & 0xf9f0) | ((newValue & 0x30) << 5) | (newValue & 0x0f);
|
||||
@@ -334,6 +344,7 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if ((newValue & 0xffff) > 0x1f) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"relocation out of range", elfRelocationContext.getLog());
|
||||
// continue to apply
|
||||
}
|
||||
|
||||
newValue = (oldValue & 0xff07) | ((newValue & 0x1f) << 3);
|
||||
@@ -351,8 +362,9 @@ public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
default:
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-7
@@ -801,7 +801,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||
catch (NotFoundException e) {
|
||||
throw new AssertException("unexpected", e);
|
||||
}
|
||||
catch (MemoryAccessException | AddressOverflowException e) {
|
||||
catch (MemoryAccessException e) {
|
||||
elfLoadHelper.log("Failed to adjust GOT: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -855,14 +855,14 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||
catch (NotFoundException e) {
|
||||
throw new AssertException("unexpected", e);
|
||||
}
|
||||
catch (MemoryAccessException | AddressOverflowException e) {
|
||||
catch (MemoryAccessException e) {
|
||||
elfLoadHelper.log("Failed to adjust MIPS GOT: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private Address adjustTableEntryIfNonZero(Address tableBaseAddr, int entryIndex,
|
||||
long adjustment, ElfLoadHelper elfLoadHelper)
|
||||
throws MemoryAccessException, AddressOverflowException {
|
||||
throws MemoryAccessException {
|
||||
boolean is64Bit = elfLoadHelper.getElfHeader().is64Bit();
|
||||
Memory memory = elfLoadHelper.getProgram().getMemory();
|
||||
Address tableEntryAddr;
|
||||
@@ -871,7 +871,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||
if (adjustment != 0) {
|
||||
long offset = memory.getLong(tableEntryAddr);
|
||||
if (offset != 0) {
|
||||
elfLoadHelper.addFakeRelocTableEntry(tableEntryAddr, 8);
|
||||
elfLoadHelper.addArtificialRelocTableEntry(tableEntryAddr, 8);
|
||||
memory.setLong(tableEntryAddr, offset + adjustment);
|
||||
}
|
||||
}
|
||||
@@ -881,7 +881,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||
if (adjustment != 0) {
|
||||
int offset = memory.getInt(tableEntryAddr);
|
||||
if (offset != 0) {
|
||||
elfLoadHelper.addFakeRelocTableEntry(tableEntryAddr, 4);
|
||||
elfLoadHelper.addArtificialRelocTableEntry(tableEntryAddr, 4);
|
||||
memory.setInt(tableEntryAddr, (int) (offset + adjustment));
|
||||
}
|
||||
}
|
||||
@@ -898,7 +898,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||
tableEntryAddr = tableBaseAddr.add(entryIndex * 8);
|
||||
long offset = memory.getLong(tableEntryAddr);
|
||||
if (offset == 0) {
|
||||
elfLoadHelper.addFakeRelocTableEntry(tableEntryAddr, 8);
|
||||
elfLoadHelper.addArtificialRelocTableEntry(tableEntryAddr, 8);
|
||||
memory.setLong(tableEntryAddr, value);
|
||||
}
|
||||
}
|
||||
@@ -906,7 +906,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||
tableEntryAddr = tableBaseAddr.add(entryIndex * 4);
|
||||
int offset = memory.getInt(tableEntryAddr);
|
||||
if (offset == 0) {
|
||||
elfLoadHelper.addFakeRelocTableEntry(tableEntryAddr, 4);
|
||||
elfLoadHelper.addArtificialRelocTableEntry(tableEntryAddr, 4);
|
||||
memory.setInt(tableEntryAddr, (int) value);
|
||||
}
|
||||
}
|
||||
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.elf.relocation;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.MemoryBlockUtils;
|
||||
import ghidra.app.util.bin.format.elf.*;
|
||||
import ghidra.app.util.bin.format.elf.extend.MIPS_ElfExtension;
|
||||
import ghidra.app.util.bin.format.elf.relocation.MIPS_ElfRelocationHandler.MIPS_DeferredRelocation;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
/**
|
||||
* {@link MIPS_ElfRelocationContext} provides extended relocation context with the ability
|
||||
* to retain deferred relocation lists. In addition, the ability to generate a section GOT
|
||||
* table is provided to facilitate relocations encountered within object modules.
|
||||
*/
|
||||
class MIPS_ElfRelocationContext extends ElfRelocationContext {
|
||||
|
||||
private LinkedList<MIPS_DeferredRelocation> hi16list = new LinkedList<>();
|
||||
private LinkedList<MIPS_DeferredRelocation> got16list = new LinkedList<>();
|
||||
|
||||
private AddressRange sectionGotLimits;
|
||||
private Address sectionGotAddress;
|
||||
private Address lastSectionGotEntryAddress;
|
||||
private Address nextSectionGotEntryAddress;
|
||||
|
||||
private Map<Long, Address> gotMap;
|
||||
|
||||
boolean useSavedAddend = false;
|
||||
boolean savedAddendHasError = false;
|
||||
long savedAddend;
|
||||
|
||||
Address lastSymbolAddr;
|
||||
|
||||
MIPS_ElfRelocationContext(MIPS_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
super(handler, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endRelocationTableProcessing() {
|
||||
|
||||
// Mark all deferred relocations which were never processed
|
||||
for (MIPS_DeferredRelocation reloc : hi16list) {
|
||||
reloc.markUnprocessed(this, "LO16 Relocation");
|
||||
}
|
||||
hi16list.clear();
|
||||
for (MIPS_DeferredRelocation reloc : got16list) {
|
||||
reloc.markUnprocessed(this, "LO16 Relocation");
|
||||
}
|
||||
got16list.clear();
|
||||
|
||||
// Generate the section GOT table if required
|
||||
createGot();
|
||||
|
||||
sectionGotLimits = null;
|
||||
sectionGotAddress = null;
|
||||
lastSectionGotEntryAddress = null;
|
||||
nextSectionGotEntryAddress = null;
|
||||
gotMap = null;
|
||||
useSavedAddend = false;
|
||||
savedAddendHasError = false;
|
||||
lastSymbolAddr = null;
|
||||
|
||||
super.endRelocationTableProcessing();
|
||||
}
|
||||
|
||||
private void allocateSectionGot() {
|
||||
int alignment = getLoadAdapter().getLinkageBlockAlignment();
|
||||
sectionGotLimits =
|
||||
getLoadHelper().allocateLinkageBlock(alignment, 0x10000, getSectionGotName());
|
||||
sectionGotAddress =
|
||||
sectionGotLimits != null ? sectionGotLimits.getMinAddress() : Address.NO_ADDRESS;
|
||||
nextSectionGotEntryAddress = sectionGotAddress;
|
||||
if (sectionGotLimits == null) {
|
||||
loadHelper.log("Failed to allocate " + getSectionGotName() +
|
||||
" block required for relocation processing");
|
||||
}
|
||||
else {
|
||||
loadHelper.log("Created " + getSectionGotName() +
|
||||
" block required for relocation processing (gp=0x" +
|
||||
Long.toHexString(getGPValue()) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate the next section GOT entry location.
|
||||
* @return Address of GOT entry or null if unable to allocate.
|
||||
*/
|
||||
private Address getNextSectionGotEntryAddress() {
|
||||
if (nextSectionGotEntryAddress == null) {
|
||||
allocateSectionGot();
|
||||
}
|
||||
Address addr = nextSectionGotEntryAddress;
|
||||
if (addr != Address.NO_ADDRESS) {
|
||||
try {
|
||||
int pointerSize = loadHelper.getProgram().getDefaultPointerSize();
|
||||
Address lastAddr = nextSectionGotEntryAddress.addNoWrap(pointerSize - 1);
|
||||
if (sectionGotLimits.contains(lastAddr)) {
|
||||
lastSectionGotEntryAddress = lastAddr;
|
||||
nextSectionGotEntryAddress = lastSectionGotEntryAddress.addNoWrap(1);
|
||||
if (!sectionGotLimits.contains(nextSectionGotEntryAddress)) {
|
||||
nextSectionGotEntryAddress = Address.NO_ADDRESS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// unable to allocation entry size
|
||||
nextSectionGotEntryAddress = Address.NO_ADDRESS;
|
||||
return Address.NO_ADDRESS;
|
||||
}
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
nextSectionGotEntryAddress = Address.NO_ADDRESS;
|
||||
}
|
||||
}
|
||||
return addr != Address.NO_ADDRESS ? addr : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the preferred GP.
|
||||
* NOTE: This needs work to properly handle the use of multiple GP's
|
||||
* @return preferred GP value or -1 if unable to determine GP
|
||||
*/
|
||||
public long getGPValue() {
|
||||
|
||||
long gp = getAdjustedGPValue();
|
||||
if (gp == -1) {
|
||||
|
||||
// TODO: we should probably not resort to assuming use of fabricated got so easily
|
||||
// since getAdjustedGPValue has rather limited capability at present
|
||||
|
||||
// assume GP relative to fabricated GOT
|
||||
if (sectionGotAddress == null) {
|
||||
allocateSectionGot();
|
||||
}
|
||||
if (sectionGotAddress == Address.NO_ADDRESS) {
|
||||
return -1;
|
||||
}
|
||||
// gp is defined as 0x7ff0 byte offset into the global offset table
|
||||
return sectionGotAddress.getOffset() + 0x7ff0;
|
||||
}
|
||||
|
||||
return gp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean extractAddend() {
|
||||
return !relocationTable.hasAddendRelocations() && !useSavedAddend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the next relocation has the same offset.
|
||||
* If true, the computed value should be stored to savedAddend and
|
||||
* useSaveAddend set true.
|
||||
* @param relocation current relocation
|
||||
* @return true if next relocation has same offset
|
||||
*/
|
||||
boolean nextRelocationHasSameOffset(ElfRelocation relocation) {
|
||||
ElfRelocation[] relocations = relocationTable.getRelocations();
|
||||
int relocIndex = relocation.getRelocationIndex();
|
||||
if (relocIndex < 0 || relocIndex >= (relocations.length - 1)) {
|
||||
return false;
|
||||
}
|
||||
return relocations[relocIndex].getOffset() == relocations[relocIndex + 1].getOffset() &&
|
||||
relocations[relocIndex + 1].getType() != MIPS_ElfRelocationConstants.R_MIPS_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or allocate a GOT entry for the specified symbolValue
|
||||
* @param symbolValue symbol value to be added to GOT
|
||||
* @return GOT entry address or null if unable to allocate
|
||||
*/
|
||||
public Address getSectionGotAddress(long symbolValue) {
|
||||
Address addr = null;
|
||||
if (gotMap == null) {
|
||||
gotMap = new HashMap<>();
|
||||
}
|
||||
else {
|
||||
addr = gotMap.get(symbolValue);
|
||||
}
|
||||
if (addr == null) {
|
||||
addr = getNextSectionGotEntryAddress();
|
||||
if (addr == null) {
|
||||
return null;
|
||||
}
|
||||
gotMap.put(symbolValue, addr);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
private String getSectionGotName() {
|
||||
String sectionName = relocationTable.getSectionToBeRelocated().getNameAsString();
|
||||
return ElfRelocationHandler.GOT_BLOCK_NAME + sectionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the section GOT table to a new %got memory block
|
||||
*/
|
||||
private void createGot() {
|
||||
if (lastSectionGotEntryAddress == null) {
|
||||
return;
|
||||
}
|
||||
int size = (int) lastSectionGotEntryAddress.subtract(sectionGotAddress) + 1;
|
||||
String blockName = getSectionGotName();
|
||||
try {
|
||||
MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false,
|
||||
blockName, sectionGotAddress, size,
|
||||
"NOTE: This block is artificial and allows ELF Relocations to work correctly",
|
||||
"Elf Loader", true, false, false, loadHelper.getLog());
|
||||
DataConverter converter =
|
||||
program.getMemory().isBigEndian() ? BigEndianDataConverter.INSTANCE
|
||||
: LittleEndianDataConverter.INSTANCE;
|
||||
for (long symbolValue : gotMap.keySet()) {
|
||||
Address addr = gotMap.get(symbolValue);
|
||||
byte[] bytes;
|
||||
if (program.getDefaultPointerSize() == 4) {
|
||||
bytes = converter.getBytes((int) symbolValue);
|
||||
}
|
||||
else {
|
||||
bytes = converter.getBytes(symbolValue);
|
||||
}
|
||||
block.putBytes(addr, bytes);
|
||||
loadHelper.createData(addr, PointerDataType.dataType);
|
||||
}
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
throw new AssertException(e); // unexpected
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the GP value
|
||||
* @return adjusted GP value or -1 if _mips_gp_value symbol not defined.
|
||||
*/
|
||||
long getAdjustedGPValue() {
|
||||
|
||||
// TODO: this is a simplified use of GP and could be incorrect when multiple GPs exist
|
||||
|
||||
Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program,
|
||||
MIPS_ElfExtension.MIPS_GP_VALUE_SYMBOL, err -> getLog().error("MIPS_ELF", err));
|
||||
if (symbol == null) {
|
||||
return -1;
|
||||
}
|
||||
return symbol.getAddress().getOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the GP0 value (from .reginfo and generated symbol)
|
||||
* @param mipsRelocationContext
|
||||
* @return adjusted GP0 value or -1 if _mips_gp0_value symbol not defined.
|
||||
*/
|
||||
long getGP0Value() {
|
||||
Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program,
|
||||
MIPS_ElfExtension.MIPS_GP0_VALUE_SYMBOL, err -> getLog().error("MIPS_ELF", err));
|
||||
if (symbol == null) {
|
||||
return -1;
|
||||
}
|
||||
return symbol.getAddress().getOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSymbolValue(ElfSymbol symbol) {
|
||||
if ("__gnu_local_gp".equals(symbol.getNameAsString())) {
|
||||
return getAdjustedGPValue(); // TODO: need to verify this case still
|
||||
}
|
||||
return super.getSymbolValue(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over deferred HI16 relocations. Iterator may be used to remove
|
||||
* entries as they are processed.
|
||||
* @return HI16 relocation iterator
|
||||
*/
|
||||
Iterator<MIPS_DeferredRelocation> iterateHi16() {
|
||||
return hi16list.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add HI16 relocation for deferred processing
|
||||
* @param hi16reloc HI16 relocation
|
||||
*/
|
||||
void addHI16Relocation(MIPS_DeferredRelocation hi16reloc) {
|
||||
hi16list.add(hi16reloc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over deferred GOT16 relocations. Iterator may be used to remove
|
||||
* entries as they are processed.
|
||||
* @return GOT16 relocation iterator
|
||||
*/
|
||||
Iterator<MIPS_DeferredRelocation> iterateGot16() {
|
||||
return got16list.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add HI16 relocation for deferred processing
|
||||
* @param hi16reloc HI16 relocation
|
||||
*/
|
||||
void addGOT16Relocation(MIPS_DeferredRelocation got16reloc) {
|
||||
got16list.add(got16reloc);
|
||||
}
|
||||
}
|
||||
+69
-326
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user