mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02: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:
parent
f022b9a4d5
commit
5b433f35ca
63 changed files with 2146 additions and 1147 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
@ -53,11 +55,15 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,8 +108,10 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
* support. Added support for auto-named TypeDef datatypes.
|
||||
* Transitioned string data translation storage to use address-based
|
||||
* 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";
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -17,16 +17,14 @@ 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.importer.MessageLog;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
@ -48,13 +46,14 @@ public class MIPS_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_MIPS) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
MIPS_ElfRelocationContext mipsRelocationContext =
|
||||
|
@ -67,17 +66,24 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
boolean saveValueForNextReloc =
|
||||
mipsRelocationContext.nextRelocationHasSameOffset(relocation);
|
||||
|
||||
RelocationResult lastResult = RelocationResult.FAILURE;
|
||||
if (elf.is64Bit()) {
|
||||
// Each relocation can pack upto 3 relocations for 64-bit
|
||||
for (int n = 0; n < 3; n++) {
|
||||
|
||||
int relocType = type & 0xff;
|
||||
type >>= 8;
|
||||
int nextRelocType = (n < 2) ? (type & 0xff) : 0;
|
||||
int nextRelocType =
|
||||
(n < 2) ? (type & 0xff) : MIPS_ElfRelocationConstants.R_MIPS_NONE;
|
||||
|
||||
doRelocate(mipsRelocationContext, relocType, symbolIndex, relocation,
|
||||
RelocationResult result = doRelocate(mipsRelocationContext, relocType, symbolIndex,
|
||||
relocation,
|
||||
relocationAddress, nextRelocType != MIPS_ElfRelocationConstants.R_MIPS_NONE ||
|
||||
saveValueForNextReloc);
|
||||
if (result.status() == Status.FAILURE || result.status() == Status.UNSUPPORTED) {
|
||||
return result;
|
||||
}
|
||||
lastResult = result;
|
||||
|
||||
symbolIndex = 0; // set to STN_UNDEF(0) once symbol used by first relocation
|
||||
|
||||
|
@ -85,11 +91,11 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
break;
|
||||
}
|
||||
}
|
||||
return lastResult;
|
||||
}
|
||||
else {
|
||||
doRelocate(mipsRelocationContext, type, symbolIndex, relocation, relocationAddress,
|
||||
saveValueForNextReloc);
|
||||
}
|
||||
|
||||
return doRelocate(mipsRelocationContext, type, symbolIndex, relocation, relocationAddress,
|
||||
saveValueForNextReloc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,15 +107,17 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
* @param saveValue true if result value should be stored in mipsRelocationContext.savedAddend
|
||||
* and mipsRelocationContext.useSavedAddend set true. If false, result value should be written
|
||||
* to relocationAddress per relocation type.
|
||||
* @return applied relocation result
|
||||
* @throws MemoryAccessException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
private void doRelocate(MIPS_ElfRelocationContext mipsRelocationContext, int relocType,
|
||||
private RelocationResult doRelocate(MIPS_ElfRelocationContext mipsRelocationContext,
|
||||
int relocType,
|
||||
int symbolIndex, ElfRelocation relocation, Address relocationAddress, boolean saveValue)
|
||||
throws MemoryAccessException, NotFoundException, AddressOutOfBoundsException {
|
||||
|
||||
if (relocType == MIPS_ElfRelocationConstants.R_MIPS_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
Program program = mipsRelocationContext.getProgram();
|
||||
|
@ -138,7 +146,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
"Stacked relocation failure", log);
|
||||
mipsRelocationContext.useSavedAddend = saveValue;
|
||||
mipsRelocationContext.savedAddend = 0;
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
addend = mipsRelocationContext.savedAddend;
|
||||
}
|
||||
|
@ -173,7 +181,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
int oldValue =
|
||||
|
@ -182,6 +190,9 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
int newValue = 0; // value blended with oldValue as appropriate for relocation
|
||||
boolean writeNewValue = false;
|
||||
|
||||
Status status = Status.PARTIAL;
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (relocType) {
|
||||
|
||||
case MIPS_ElfRelocationConstants.R_MIPS_GOT_OFST:
|
||||
|
@ -215,7 +226,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
"Relocation Failed, unable to allocate GOT entry for relocation symbol: " +
|
||||
symbolName,
|
||||
mipsRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
value = (int) getGpOffset(mipsRelocationContext, gotAddr.getOffset());
|
||||
|
@ -227,7 +238,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
newValue = (oldValue & ~0xffff) | (value & 0xffff);
|
||||
|
@ -248,7 +259,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
"Relocation Failed, unable to allocate GOT entry for relocation symbol: " +
|
||||
symbolName,
|
||||
mipsRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
// use address offset within section GOT as symbol value
|
||||
|
@ -261,7 +272,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
int appliedValue;
|
||||
|
@ -285,7 +296,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
MIPS_DeferredRelocation got16reloc = new MIPS_DeferredRelocation(relocType,
|
||||
elfSymbol, relocationAddress, oldValue, (int) addend, isGpDisp);
|
||||
mipsRelocationContext.addGOT16Relocation(got16reloc);
|
||||
break;
|
||||
break; // report as 4-byte applied even though it is deferred (could still fail)
|
||||
}
|
||||
|
||||
// fall-through
|
||||
|
@ -303,7 +314,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
"Relocation Failed, unable to allocate GOT entry for relocation symbol: " +
|
||||
symbolName,
|
||||
mipsRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
value = (int) getGpOffset(mipsRelocationContext, gotAddr.getOffset());
|
||||
|
@ -315,7 +326,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
newValue = (oldValue & ~0xffff) | (value & 0xffff);
|
||||
|
@ -334,7 +345,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
"Relocation Failed, unable to allocate GOT entry for relocation symbol: " +
|
||||
symbolName,
|
||||
mipsRelocationContext.getLog());
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
value = (int) getGpOffset(mipsRelocationContext, gotAddr.getOffset());
|
||||
|
@ -346,7 +357,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
newValue = (oldValue & ~0xffff) | (((value + 0x8000) >> 16) & 0xffff);
|
||||
|
@ -356,11 +367,19 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case MIPS_ElfRelocationConstants.R_MIPS_HI16:
|
||||
case MIPS_ElfRelocationConstants.R_MIPS16_HI16:
|
||||
case MIPS_ElfRelocationConstants.R_MICROMIPS_HI16:
|
||||
// Verify the we have GP
|
||||
if (mipsRelocationContext.getGPValue() == -1) {
|
||||
markAsError(mipsRelocationContext.getProgram(), relocationAddress,
|
||||
Integer.toString(relocType), elfSymbol.getNameAsString(),
|
||||
"Failed to perform GP-based relocation", mipsRelocationContext.getLog());
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
// Defer processing of HI16 relocations until suitable LO16 relocation is processed
|
||||
MIPS_DeferredRelocation hi16reloc = new MIPS_DeferredRelocation(relocType,
|
||||
elfSymbol, relocationAddress, oldValue, (int) addend, isGpDisp);
|
||||
mipsRelocationContext.addHI16Relocation(hi16reloc);
|
||||
break;
|
||||
break; // report as 4-byte applied even though it is deferred
|
||||
|
||||
case MIPS_ElfRelocationConstants.R_MIPS_LO16:
|
||||
case MIPS_ElfRelocationConstants.R_MIPS16_LO16:
|
||||
|
@ -384,7 +403,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
if (relocType == MIPS_ElfRelocationConstants.R_MIPS16_LO16) {
|
||||
value -= (offset & ~0x3);
|
||||
|
@ -427,9 +446,11 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
else {
|
||||
if (elf.is64Bit()) {
|
||||
memory.setLong(relocationAddress, newValueBig);
|
||||
byteLength = 8;
|
||||
}
|
||||
else {
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
byteLength = 4;
|
||||
}
|
||||
if (symbolIndex != 0 && intAddend != 0 && !saveValue) {
|
||||
// If not continuing with compound relocation (64-bit only)
|
||||
|
@ -438,6 +459,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
symbolAddr, symbolName, intAddend, mipsRelocationContext.getLog());
|
||||
applyComponentOffsetPointer(program, relocationAddress, intAddend);
|
||||
}
|
||||
status = Status.APPLIED;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -480,6 +502,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
else {
|
||||
memory.setLong(relocationAddress, newValueBig);
|
||||
status = Status.APPLIED;
|
||||
Address addr =
|
||||
symbolIndex == 0 ? mipsRelocationContext.lastSymbolAddr : symbolAddr;
|
||||
if (addr != null && addend != 0) {
|
||||
|
@ -542,6 +565,8 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
// }
|
||||
// else {
|
||||
// memory.setLong(relocationAddress, newValueBig);
|
||||
// byteLength = 8;
|
||||
// status = Status.APPLIED;
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
|
@ -567,6 +592,8 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
// }
|
||||
// else {
|
||||
// memory.setLong(relocationAddress, newValueBig);
|
||||
// byteLength = 8;
|
||||
// status = Status.APPLIED;
|
||||
// }
|
||||
// break;
|
||||
|
||||
|
@ -633,7 +660,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
if (gp0 == 0) {
|
||||
gp0 = mipsRelocationContext.getImageBaseWordAdjustmentOffset();
|
||||
|
@ -648,7 +675,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
value = (int) (symbolValue + addend - gp + gp0);
|
||||
|
@ -672,6 +699,8 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
else {
|
||||
memory.setLong(relocationAddress, newValueBig);
|
||||
byteLength = 8;
|
||||
status = Status.APPLIED;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -682,7 +711,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case MIPS_ElfRelocationConstants.R_MIPS_JUMP_SLOT:
|
||||
if (saveValue) {
|
||||
|
@ -690,10 +719,13 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
else if (mipsRelocationContext.getElfHeader().is64Bit()) {
|
||||
memory.setLong(relocationAddress, symbolValue);
|
||||
byteLength = 8;
|
||||
}
|
||||
else {
|
||||
memory.setInt(relocationAddress, (int) symbolValue);
|
||||
byteLength = 8;
|
||||
}
|
||||
status = Status.APPLIED;
|
||||
break;
|
||||
|
||||
case MIPS_ElfRelocationConstants.R_MIPS_JALR:
|
||||
|
@ -727,11 +759,12 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
int jalrBits = 0x0c000000 | offsetBits;
|
||||
memory.setInt(relocationAddress, jalrBits);
|
||||
}
|
||||
status = Status.APPLIED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// assume OK for internal function linkage
|
||||
success = true; // do nothing
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -740,6 +773,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
relocType == MIPS_ElfRelocationConstants.R_MIPS_JALR ? "R_MIPS_JALR"
|
||||
: "R_MICROMIPS_JALR",
|
||||
symbolName, "Failed to establish external linkage", log);
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -749,7 +783,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (saveValue) {
|
||||
mipsRelocationContext.savedAddendHasError = true;
|
||||
}
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (writeNewValue) {
|
||||
|
@ -763,11 +797,12 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
// to be written to relocationAddress.
|
||||
memory.setInt(relocationAddress,
|
||||
shuffle(newValue, relocType, mipsRelocationContext));
|
||||
status = Status.APPLIED;
|
||||
}
|
||||
}
|
||||
|
||||
mipsRelocationContext.useSavedAddend = saveValue;
|
||||
|
||||
return new RelocationResult(status, byteLength);
|
||||
}
|
||||
|
||||
private boolean isMIPS16Reloc(int type) {
|
||||
|
@ -1035,303 +1070,11 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
return value - gp;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>MIPS_ElfRelocationContext</code> 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.
|
||||
*/
|
||||
private static 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;
|
||||
|
||||
private boolean useSavedAddend = false;
|
||||
private boolean savedAddendHasError = false;
|
||||
private long savedAddend;
|
||||
|
||||
private 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
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>MIPS_DeferredRelocation</code> is used to capture a relocation whose processing
|
||||
* must be deferred.
|
||||
*/
|
||||
private static class MIPS_DeferredRelocation {
|
||||
static class MIPS_DeferredRelocation {
|
||||
|
||||
final int relocType;
|
||||
final ElfSymbol elfSymbol;
|
||||
|
|
|
@ -23,6 +23,8 @@ import ghidra.program.model.lang.Register;
|
|||
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 PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
@ -122,12 +124,13 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, Address relocationAddress)
|
||||
public RelocationResult relocate(ElfRelocationContext elfRelocationContext,
|
||||
ElfRelocation relocation, Address relocationAddress)
|
||||
throws MemoryAccessException, NotFoundException {
|
||||
|
||||
int type = relocation.getType();
|
||||
if (type == R_PIC30_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
@ -146,6 +149,8 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
short oldShortValue = memory.getShort(relocationAddress);
|
||||
|
||||
int newValue;
|
||||
int byteLength = 2; // most relocations affect 2-bytes (change if different)
|
||||
|
||||
|
||||
ElfHeader elf = elfRelocationContext.getElfHeader();
|
||||
if (elf.e_machine() == ElfConstants.EM_DSPIC30F) {
|
||||
|
@ -158,6 +163,7 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case R_PIC30_32: // 3
|
||||
newValue = symbolValue + addend + oldValue;
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case R_PIC30_FILE_REG_BYTE: // 4 short
|
||||
case R_PIC30_FILE_REG: // 5 short
|
||||
|
@ -175,6 +181,7 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
reloc &= 0x7fff;
|
||||
newValue = (reloc << 4) | (oldValue & ~0x7fff0);
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case R_PIC30_WORD: // 8
|
||||
case R_PIC30_WORD_TBLOFFSET: // 0x15
|
||||
|
@ -184,6 +191,7 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
reloc &= 0xffff;
|
||||
newValue = (reloc << 4) | (oldValue & ~0x0ffff0);
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case R_PIC30_WORD_TBLPAGE: // 0x18
|
||||
reloc = symbolValue >> 16;
|
||||
|
@ -195,6 +203,7 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
newValue = (reloc << 4) | (oldValue & ~0x0ffff0);
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case R_PIC30_PCREL_BRANCH: // 0x1c
|
||||
newValue = (int) (symbolValue - relocWordOffset + oldShortValue - 2);
|
||||
|
@ -205,9 +214,10 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
String symbolName = elfRelocationContext.getSymbolName(symbolIndex);
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ public class PowerPC_ElfExtension extends ElfExtension {
|
|||
// Update first got entry normally updated by link editor to refer to dynamic table
|
||||
int dynamicOffset =
|
||||
memory.getInt(gotAddr) + (int) elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
||||
elfLoadHelper.addFakeRelocTableEntry(gotAddr, 4);
|
||||
elfLoadHelper.addArtificialRelocTableEntry(gotAddr, 4);
|
||||
memory.setInt(gotAddr, dynamicOffset);
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
|
|
|
@ -22,6 +22,8 @@ import ghidra.program.model.address.Address;
|
|||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.util.*;
|
||||
|
@ -35,12 +37,13 @@ public class PowerPC64_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_PPC64 || !elf.is64Bit()) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
@ -48,7 +51,7 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
int type = relocation.getType();
|
||||
if (type == PowerPC64_ElfRelocationConstants.R_PPC64_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
||||
|
@ -72,6 +75,7 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
int oldValue = memory.getInt(relocationAddress);
|
||||
int newValue = 0;
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
// IMPORTANT NOTE:
|
||||
// Handling of Object modules (*.o) is currently problematic since relocations
|
||||
|
@ -93,11 +97,11 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
MessageLog log = elfRelocationContext.getLog();
|
||||
Symbol tocBaseSym = SymbolUtilities.getLabelOrFunctionSymbol(program,
|
||||
PowerPC64_ElfExtension.TOC_BASE, err -> log.error("PPC_ELF", err));
|
||||
PowerPC64_ElfExtension.TOC_BASE, err -> log.appendMsg(err));
|
||||
if (tocBaseSym == null) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"TOC_BASE unknown", log);
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
toc = tocBaseSym.getAddress().getOffset();
|
||||
break;
|
||||
|
@ -108,7 +112,7 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case PowerPC64_ElfRelocationConstants.R_PPC64_COPY:
|
||||
markAsWarning(program, relocationAddress, "R_PPC64_COPY", symbolName,
|
||||
symbolIndex, "Runtime copy not supported", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR32:
|
||||
newValue = (int) (symbolValue + addend);
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
|
@ -122,39 +126,47 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR16:
|
||||
newValue = (int) (symbolValue + addend);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR16_LO:
|
||||
newValue = (int) (symbolValue + addend);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_TOC16_LO:
|
||||
newValue = (int) (symbolValue + addend - toc);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_TOC16_LO_DS:
|
||||
newValue = (int) ((symbolValue + addend - toc) >> 2);
|
||||
newValue = ((oldValue >>> 16) & 0x3) | (newValue << 2);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR16_HI:
|
||||
newValue = (int) (symbolValue + addend);
|
||||
newValue = ((newValue >> 16) & 0xFFFF);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_TOC16_HI:
|
||||
newValue = (int) (symbolValue + addend - toc);
|
||||
newValue = ((newValue >> 16) & 0xFFFF);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR16_HA:
|
||||
newValue = (int) (symbolValue + addend);
|
||||
newValue = ((newValue >> 16) + (((newValue & 0x8000) != 0) ? 1 : 0));
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_TOC16_HA:
|
||||
newValue = (int) (symbolValue + addend - toc);
|
||||
newValue = ((newValue >> 16) + (((newValue & 0x8000) != 0) ? 1 : 0));
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR14:
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR14_BRTAKEN:
|
||||
|
@ -177,6 +189,7 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case PowerPC64_ElfRelocationConstants.R_PPC64_RELATIVE:
|
||||
long value64 = elfRelocationContext.getImageBaseWordAdjustmentOffset() + addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
byteLength = 8;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_REL32:
|
||||
newValue = (int) (symbolValue + addend - offset);
|
||||
|
@ -203,12 +216,14 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
// If symbol is in EXTERNAL block, we don't have descriptor entry;
|
||||
// just fill-in first slot with EXTERNAL address
|
||||
memory.setLong(relocationAddress, symbolValue);
|
||||
byteLength = 8;
|
||||
}
|
||||
else {
|
||||
// Copy function descriptor data
|
||||
byte[] bytes = new byte[24]; // TODO: can descriptor size vary ?
|
||||
memory.getBytes(functionDescriptorAddr, bytes);
|
||||
memory.setBytes(relocationAddress, bytes);
|
||||
byteLength = bytes.length;
|
||||
}
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_UADDR32:
|
||||
|
@ -218,12 +233,14 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case PowerPC64_ElfRelocationConstants.R_PPC64_UADDR16:
|
||||
newValue = (int) (symbolValue + addend);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_UADDR64:
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR64:
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_GLOB_DAT:
|
||||
value64 = symbolValue + addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
byteLength = 8;
|
||||
if (addend != 0) {
|
||||
warnExternalOffsetRelocation(program, relocationAddress,
|
||||
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
|
||||
|
@ -232,13 +249,14 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
break;
|
||||
case PowerPC64_ElfRelocationConstants.R_PPC64_TOC:
|
||||
memory.setLong(relocationAddress, toc);
|
||||
byteLength = 8;
|
||||
break;
|
||||
default:
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,6 +29,8 @@ import ghidra.program.model.lang.Register;
|
|||
import ghidra.program.model.listing.ContextChangeException;
|
||||
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.program.model.symbol.*;
|
||||
import ghidra.util.exception.*;
|
||||
|
||||
|
@ -46,7 +48,8 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
public RelocationResult relocate(ElfRelocationContext elfRelocationContext,
|
||||
ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
PowerPC_ElfRelocationContext ppcRelocationContext =
|
||||
|
@ -54,7 +57,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
ElfHeader elf = ppcRelocationContext.getElfHeader();
|
||||
if (elf.e_machine() != ElfConstants.EM_PPC || !elf.is32Bit()) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = ppcRelocationContext.getProgram();
|
||||
|
@ -62,7 +65,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
int type = relocation.getType();
|
||||
if (type == PowerPC_ElfRelocationConstants.R_PPC_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
||||
|
@ -72,6 +75,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
markAsError(program, relocationAddress, Long.toString(type), null,
|
||||
"Unsupported language for 32-bit PowerPC relocation",
|
||||
ppcRelocationContext.getLog());
|
||||
// TODO: should we return failure status?
|
||||
}
|
||||
|
||||
// NOTE: Based upon glibc source it appears that PowerPC only uses RELA relocations
|
||||
|
@ -100,11 +104,13 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
int oldValue = memory.getInt(relocationAddress);
|
||||
int newValue = 0;
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (type) {
|
||||
case PowerPC_ElfRelocationConstants.R_PPC_COPY:
|
||||
markAsWarning(program, relocationAddress, "R_PPC_COPY", symbolName,
|
||||
symbolIndex, "Runtime copy not supported", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.SKIPPED;
|
||||
case PowerPC_ElfRelocationConstants.R_PPC_ADDR32:
|
||||
case PowerPC_ElfRelocationConstants.R_PPC_UADDR32:
|
||||
case PowerPC_ElfRelocationConstants.R_PPC_GLOB_DAT:
|
||||
|
@ -126,10 +132,12 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case PowerPC_ElfRelocationConstants.R_PPC_ADDR16_LO:
|
||||
newValue = symbolValue + addend;
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC_ElfRelocationConstants.R_PPC_ADDR16_HI:
|
||||
newValue = (symbolValue + addend) >> 16;
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
/**
|
||||
*
|
||||
|
@ -163,6 +171,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case PowerPC_ElfRelocationConstants.R_PPC_ADDR16_HA:
|
||||
newValue = (symbolValue + addend + 0x8000) >> 16;
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case PowerPC_ElfRelocationConstants.R_PPC_ADDR14:
|
||||
case PowerPC_ElfRelocationConstants.R_PPC_ADDR14_BRTAKEN:
|
||||
|
@ -220,6 +229,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
// and we may only have room in the plt for two instructions.
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
ppcRelocationContext.getLog());
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
break;
|
||||
case PowerPC_ElfRelocationConstants.R_PPC_EMB_SDA21:
|
||||
|
@ -255,13 +265,13 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"Unsupported relocation for external symbol",
|
||||
ppcRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
}
|
||||
if (gprID == null || sdaBase == null) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"Failed to identfy appropriate data block", ppcRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
newValue = (symbolValue - sdaBase + addend) & 0xffff;
|
||||
|
@ -273,8 +283,9 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
default:
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
ppcRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,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 RISCV_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
@ -31,11 +33,12 @@ public class RISCV_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 (!canRelocate(elf)) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
@ -43,7 +46,7 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
boolean is32 = elf.is32Bit();
|
||||
int type = relocation.getType();
|
||||
if (RISCV_ElfRelocationConstants.R_RISCV_NONE == type) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
long addend = relocation.hasAddend() ? relocation.getAddend() : is32 ? memory.getInt(relocationAddress) : memory.getLong(relocationAddress);
|
||||
|
@ -78,389 +81,428 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
short value16 = 0;
|
||||
byte value8 = 0;
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (type) {
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_32:
|
||||
// Runtime relocation word32 = S + A
|
||||
value32 = (int)(symbolValue + addend);
|
||||
memory.setInt(relocationAddress, value32);
|
||||
if (addend != 0) {
|
||||
warnExternalOffsetRelocation(program, relocationAddress,
|
||||
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
|
||||
if (elf.is32Bit()) {
|
||||
applyComponentOffsetPointer(program, relocationAddress, addend);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_64:
|
||||
// Runtime relocation word64 = S + A
|
||||
value64 = symbolValue + addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
if (addend != 0) {
|
||||
warnExternalOffsetRelocation(program, relocationAddress,
|
||||
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
|
||||
if (elf.is64Bit()) {
|
||||
applyComponentOffsetPointer(program, relocationAddress, addend);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RELATIVE:
|
||||
// Runtime relocation word32,64 = B + A
|
||||
if (is32) {
|
||||
value32 = (int)(base + addend);
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_32:
|
||||
// Runtime relocation word32 = S + A
|
||||
value32 = (int) (symbolValue + addend);
|
||||
memory.setInt(relocationAddress, value32);
|
||||
}
|
||||
else {
|
||||
value64 = base + addend;
|
||||
if (addend != 0) {
|
||||
warnExternalOffsetRelocation(program, relocationAddress,
|
||||
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
|
||||
if (elf.is32Bit()) {
|
||||
applyComponentOffsetPointer(program, relocationAddress, addend);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_64:
|
||||
// Runtime relocation word64 = S + A
|
||||
value64 = symbolValue + addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
}
|
||||
break;
|
||||
byteLength = 8;
|
||||
if (addend != 0) {
|
||||
warnExternalOffsetRelocation(program, relocationAddress,
|
||||
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
|
||||
if (elf.is64Bit()) {
|
||||
applyComponentOffsetPointer(program, relocationAddress, addend);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_COPY:
|
||||
// Runtime relocation must be in executable. not allowed in shared library
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_COPY", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RELATIVE:
|
||||
// Runtime relocation word32,64 = B + A
|
||||
if (is32) {
|
||||
value32 = (int) (base + addend);
|
||||
memory.setInt(relocationAddress, value32);
|
||||
}
|
||||
else {
|
||||
value64 = base + addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
byteLength = 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_COPY:
|
||||
// Runtime relocation must be in executable. not allowed in shared library
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_COPY", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_JUMP_SLOT:
|
||||
// Runtime relocation word32,64 = S ;handled by PLT unless LD_BIND_NOW
|
||||
if (is32) {
|
||||
value32 = (int)(symbolValue);
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_JUMP_SLOT:
|
||||
// Runtime relocation word32,64 = S ;handled by PLT unless LD_BIND_NOW
|
||||
if (is32) {
|
||||
value32 = (int) (symbolValue);
|
||||
memory.setInt(relocationAddress, value32);
|
||||
}
|
||||
else {
|
||||
value64 = symbolValue;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
byteLength = 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_DTPMOD32:
|
||||
// TLS relocation word32 = S->TLSINDEX
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTPMOD32", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_DTPMOD64:
|
||||
// TLS relocation word64 = S->TLSINDEX
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTPMOD32", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_DTPREL32:
|
||||
// TLS relocation word32 = TLS + S + A - TLS_TP_OFFSET
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTPREL32", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_DTPREL64:
|
||||
// TLS relocation word64 = TLS + S + A - TLS_TP_OFFSET
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTPREL64", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_TPREL32:
|
||||
// TLS relocation word32 = TLS + S + A + S_TLS_OFFSET - TLS_DTV_OFFSET
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTREL32", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_TPREL64:
|
||||
// TLS relocation word64 = TLS + S + A + S_TLS_OFFSET - TLS_DTV_OFFSET
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_TPREL64", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_BRANCH:
|
||||
// PC-relative branch (SB-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_BRANCH", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_JAL:
|
||||
// PC-relative jump (UJ-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_JAL", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_CALL:
|
||||
// PC-relative call MACRO call,tail (auipc+jalr pair)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_CALL", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_CALL_PLT:
|
||||
// PC-relative call (PLT) MACRO call,tail (auipc+jalr pair) PIC
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_CALL_PLT", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GOT_HI20:
|
||||
// PC-relative GOT reference MACRO la
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GOT_HI20", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_GOT_HI20:
|
||||
// PC-relative TLS IE GOT offset MACRO la.tls.ie
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_GOT_HI20", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_GD_HI20:
|
||||
// PC-relative TLS GD reference MACRO la.tls.gd
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_GD_HI20", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_PCREL_HI20:
|
||||
// PC-relative reference %pcrel_hi(symbol) (U-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_PCREL_HI20", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_PCREL_LO12_I:
|
||||
// PC-relative reference %pcrel_lo(symbol) (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_PCREL_LO12_I", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_PCREL_LO12_S:
|
||||
// PC-relative reference %pcrel_lo(symbol) (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_PCREL_LO12_S", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_HI20:
|
||||
// Absolute address %hi(symbol) (U-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_HI20", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_LO12_I:
|
||||
// Absolute address %lo(symbol) (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_LO12_I", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_LO12_S:
|
||||
// Absolute address %lo(symbol) (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_LO12_S", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_HI20:
|
||||
// TLS LE thread offset %tprel_hi(symbol) (U-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_HI20", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_LO12_I:
|
||||
// TLS LE thread offset %tprel_lo(symbol) (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_LO12_I", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_LO12_S:
|
||||
// TLS LE thread offset %tprel_lo(symbol) (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_LO12_S", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_ADD:
|
||||
// TLS LE thread usage %tprel_add(symbol)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_ADD", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ADD8:
|
||||
// 8-bit label addition word8 = old + S + A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ADD8", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value8 = memory.getByte(relocationAddress);
|
||||
value8 += (byte) symbolValue;
|
||||
value8 += (byte) addend;
|
||||
memory.setByte(relocationAddress, value8);
|
||||
byteLength = 1;
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ADD16:
|
||||
// 16-bit label addition word16 = old + S + A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ADD16", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value16 = memory.getShort(relocationAddress);
|
||||
value16 += (short) symbolValue;
|
||||
value16 += (short) addend;
|
||||
memory.setShort(relocationAddress, value16);
|
||||
byteLength = 2;
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ADD32:
|
||||
// 32-bit label addition word32 = old + S + A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ADD32", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value32 = memory.getInt(relocationAddress);
|
||||
value32 += (int) symbolValue;
|
||||
value32 += (int) addend;
|
||||
memory.setInt(relocationAddress, value32);
|
||||
}
|
||||
else {
|
||||
value64 = symbolValue;
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ADD64:
|
||||
// 64-bit label addition word64 = old + S + A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ADD64", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value64 = memory.getLong(relocationAddress);
|
||||
value64 += symbolValue;
|
||||
value64 += addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
}
|
||||
break;
|
||||
byteLength = 8;
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_DTPMOD32:
|
||||
// TLS relocation word32 = S->TLSINDEX
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTPMOD32", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB8:
|
||||
// 8-bit label subtraction word8 = old - S - A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB8", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
value8 = memory.getByte(relocationAddress);
|
||||
value8 -= (byte) symbolValue;
|
||||
value8 -= (byte) addend;
|
||||
memory.setByte(relocationAddress, value8);
|
||||
byteLength = 1;
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_DTPMOD64:
|
||||
// TLS relocation word64 = S->TLSINDEX
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTPMOD32", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB16:
|
||||
// 16-bit label subtraction word16 = old - S - A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB16", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
value16 = memory.getShort(relocationAddress);
|
||||
value16 -= (short) symbolValue;
|
||||
value16 -= (short) addend;
|
||||
memory.setShort(relocationAddress, value16);
|
||||
byteLength = 2;
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_DTPREL32:
|
||||
// TLS relocation word32 = TLS + S + A - TLS_TP_OFFSET
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTPREL32", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB32:
|
||||
// 32-bit label subtraction word32 = old - S - A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB32", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
value32 = memory.getInt(relocationAddress);
|
||||
value32 -= (int) symbolValue;
|
||||
value32 -= (int) addend;
|
||||
memory.setInt(relocationAddress, value32);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_DTPREL64:
|
||||
// TLS relocation word64 = TLS + S + A - TLS_TP_OFFSET
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTPREL64", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB64:
|
||||
// 64-bit label subtraction word64 = old - S - A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB64", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
value64 = memory.getLong(relocationAddress);
|
||||
value64 -= symbolValue;
|
||||
value64 -= addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
byteLength = 8;
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_TPREL32:
|
||||
// TLS relocation word32 = TLS + S + A + S_TLS_OFFSET - TLS_DTV_OFFSET
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_DTREL32", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GNU_VTINHERIT:
|
||||
// GNU C++ vtable hierarchy
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GNU_VTINHERIT", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_TPREL64:
|
||||
// TLS relocation word64 = TLS + S + A + S_TLS_OFFSET - TLS_DTV_OFFSET
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_TPREL64", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GNU_VTENTRY:
|
||||
// GNU C++ vtable member usage
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GNU_VTENTRY", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_BRANCH:
|
||||
// PC-relative branch (SB-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_BRANCH", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ALIGN:
|
||||
// Alignment statement
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ALIGN", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_JAL:
|
||||
// PC-relative jump (UJ-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_JAL", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RVC_BRANCH:
|
||||
// PC-relative branch offset (CB-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_RVC_BRANCH", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_CALL:
|
||||
// PC-relative call MACRO call,tail (auipc+jalr pair)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_CALL", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RVC_JUMP:
|
||||
// PC-relative jump offset (CJ-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_RVC_BRANCH", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_CALL_PLT:
|
||||
// PC-relative call (PLT) MACRO call,tail (auipc+jalr pair) PIC
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_CALL_PLT", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RVC_LUI:
|
||||
// Absolute address (CI-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_RVC_LUI", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GOT_HI20:
|
||||
// PC-relative GOT reference MACRO la
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GOT_HI20", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GPREL_I:
|
||||
// GP-relative reference (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GPREL_I", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_GOT_HI20:
|
||||
// PC-relative TLS IE GOT offset MACRO la.tls.ie
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_GOT_HI20", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GPREL_S:
|
||||
// GP-relative reference (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GPREL_S", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TLS_GD_HI20:
|
||||
// PC-relative TLS GD reference MACRO la.tls.gd
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TLS_GD_HI20", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_I:
|
||||
// TP-relative TLS LE load (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_I", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_PCREL_HI20:
|
||||
// PC-relative reference %pcrel_hi(symbol) (U-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_PCREL_HI20", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_S:
|
||||
// TP-relative TLS LE store (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_S", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_PCREL_LO12_I:
|
||||
// PC-relative reference %pcrel_lo(symbol) (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_PCREL_LO12_I", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RELAX:
|
||||
// Instruction pair can be relaxed
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_RELAX", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_PCREL_LO12_S:
|
||||
// PC-relative reference %pcrel_lo(symbol) (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_PCREL_LO12_S", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB6:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB6", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_HI20:
|
||||
// Absolute address %hi(symbol) (U-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_HI20", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SET6:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SET6", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_LO12_I:
|
||||
// Absolute address %lo(symbol) (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_LO12_I", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SET8:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SET8", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_LO12_S:
|
||||
// Absolute address %lo(symbol) (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_LO12_S", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SET16:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SET16", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_HI20:
|
||||
// TLS LE thread offset %tprel_hi(symbol) (U-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_HI20", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SET32:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SET32", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_LO12_I:
|
||||
// TLS LE thread offset %tprel_lo(symbol) (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_LO12_I", symbolName, symbolIndex,
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_32_PCREL:
|
||||
// 32-bit PC relative
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_32_PCREL", symbolName,
|
||||
symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_LO12_S:
|
||||
// TLS LE thread offset %tprel_lo(symbol) (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_LO12_S", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_ADD:
|
||||
// TLS LE thread usage %tprel_add(symbol)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_ADD", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ADD8:
|
||||
// 8-bit label addition word8 = old + S + A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ADD8", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value8 = memory.getByte(relocationAddress);
|
||||
value8 += (byte)symbolValue;
|
||||
value8 += (byte)addend;
|
||||
memory.setByte(relocationAddress, value8);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ADD16:
|
||||
// 16-bit label addition word16 = old + S + A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ADD16", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value16 = memory.getShort(relocationAddress);
|
||||
value16 += (short)symbolValue;
|
||||
value16 += (short)addend;
|
||||
memory.setShort(relocationAddress, value16);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ADD32:
|
||||
// 32-bit label addition word32 = old + S + A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ADD32", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value32 = memory.getInt(relocationAddress);
|
||||
value32 += (int)symbolValue;
|
||||
value32 += (int)addend;
|
||||
memory.setInt(relocationAddress, value32);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ADD64:
|
||||
// 64-bit label addition word64 = old + S + A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ADD64", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value64 = memory.getLong(relocationAddress);
|
||||
value64 += symbolValue;
|
||||
value64 += addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB8:
|
||||
// 8-bit label subtraction word8 = old - S - A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB8", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value8 = memory.getByte(relocationAddress);
|
||||
value8 -= (byte)symbolValue;
|
||||
value8 -= (byte)addend;
|
||||
memory.setByte(relocationAddress, value8);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB16:
|
||||
// 16-bit label subtraction word16 = old - S - A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB16", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value16 = memory.getShort(relocationAddress);
|
||||
value16 -= (short)symbolValue;
|
||||
value16 -= (short)addend;
|
||||
memory.setShort(relocationAddress, value16);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB32:
|
||||
// 32-bit label subtraction word32 = old - S - A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB32", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value32 = memory.getInt(relocationAddress);
|
||||
value32 -= (int)symbolValue;
|
||||
value32 -= (int)addend;
|
||||
memory.setInt(relocationAddress, value32);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB64:
|
||||
// 64-bit label subtraction word64 = old - S - A
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB64", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
value64 = memory.getLong(relocationAddress);
|
||||
value64 -= symbolValue;
|
||||
value64 -= addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GNU_VTINHERIT:
|
||||
// GNU C++ vtable hierarchy
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GNU_VTINHERIT", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GNU_VTENTRY:
|
||||
// GNU C++ vtable member usage
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GNU_VTENTRY", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_ALIGN:
|
||||
// Alignment statement
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_ALIGN", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RVC_BRANCH:
|
||||
// PC-relative branch offset (CB-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_RVC_BRANCH", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RVC_JUMP:
|
||||
// PC-relative jump offset (CJ-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_RVC_BRANCH", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RVC_LUI:
|
||||
// Absolute address (CI-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_RVC_LUI", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GPREL_I:
|
||||
// GP-relative reference (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GPREL_I", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_GPREL_S:
|
||||
// GP-relative reference (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_GPREL_S", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_I:
|
||||
// TP-relative TLS LE load (I-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_I", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_TPREL_S:
|
||||
// TP-relative TLS LE store (S-Type)
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_TPREL_S", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_RELAX:
|
||||
// Instruction pair can be relaxed
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_RELAX", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SUB6:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SUB6", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SET6:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SET6", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SET8:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SET8", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SET16:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SET16", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_SET32:
|
||||
// Local label subtraction
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_SET32", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
case RISCV_ElfRelocationConstants.R_RISCV_32_PCREL:
|
||||
// 32-bit PC relative
|
||||
markAsWarning(program, relocationAddress, "R_RISCV_32_PCREL", symbolName, symbolIndex,
|
||||
"TODO, needs support ", elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
default:
|
||||
// 58-191 Reserved Reserved for future standard use
|
||||
// 192-255 Reserved Reserved for nonstandard ABI extensions
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
default:
|
||||
// 58-191 Reserved Reserved for future standard use
|
||||
// 192-255 Reserved Reserved for nonstandard ABI extensions
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 SPARC_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
@ -32,13 +34,14 @@ public class SPARC_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_SPARC &&
|
||||
elf.e_machine() != ElfConstants.EM_SPARC32PLUS) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
@ -46,7 +49,7 @@ public class SPARC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
int type = relocation.getType();
|
||||
if (type == SPARC_ElfRelocationConstants.R_SPARC_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
@ -63,6 +66,8 @@ public class SPARC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
int oldValue = memory.getInt(relocationAddress);
|
||||
int newValue = 0;
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (type) {
|
||||
case SPARC_ElfRelocationConstants.R_SPARC_DISP32:
|
||||
newValue = (int) (symbolValue + addend - offset);
|
||||
|
@ -102,12 +107,13 @@ public class SPARC_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
case SPARC_ElfRelocationConstants.R_SPARC_COPY:
|
||||
markAsWarning(program, relocationAddress, "R_SPARC_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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 SH_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
@ -30,12 +32,13 @@ public class SH_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_SH || !elf.is32Bit()) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
@ -44,7 +47,7 @@ public class SH_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
int type = relocation.getType();
|
||||
if (type == SH_ElfRelocationConstants.R_SH_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
||||
|
@ -61,6 +64,8 @@ public class SH_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
int newValue = 0;
|
||||
int oldValue;
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (type) {
|
||||
case SH_ElfRelocationConstants.R_SH_DIR32:
|
||||
// 32-bit absolute relocation w/ addend
|
||||
|
@ -101,6 +106,7 @@ public class SH_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
newValue = ((symbolValue + addend) - offset) >> 1;
|
||||
newValue = (oldValue & 0xff00) | (newValue & 0xff);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
|
||||
case SH_ElfRelocationConstants.R_SH_IND12W: // 12-bit PC relative branch divided by 2
|
||||
|
@ -114,6 +120,7 @@ public class SH_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
newValue = ((symbolValue + addend) - offset) >> 1;
|
||||
newValue = (oldValue & 0xf000) | (newValue & 0xfff);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
|
||||
case SH_ElfRelocationConstants.R_SH_DIR8WPL: // 8-bit PC unsigned-relative branch divided by 4
|
||||
|
@ -124,12 +131,13 @@ public class SH_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
newValue = ((symbolValue + addend) - offset) >> 2;
|
||||
newValue = (oldValue & 0xff00) | (newValue & 0xff);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
byteLength = 2;
|
||||
break;
|
||||
|
||||
case SH_ElfRelocationConstants.R_SH_COPY:
|
||||
markAsWarning(program, relocationAddress, "R_SH_COPY", symbolName, symbolIndex,
|
||||
"Runtime copy not supported", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case SH_ElfRelocationConstants.R_SH_RELATIVE:
|
||||
if (elfRelocationContext.extractAddend()) {
|
||||
|
@ -142,8 +150,9 @@ public class SH_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
default:
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,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.util.exception.NotFoundException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
|
||||
public class X86_32_CoffRelocationHandler implements CoffRelocationHandler {
|
||||
|
||||
|
@ -31,15 +32,17 @@ public class X86_32_CoffRelocationHandler implements CoffRelocationHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void relocate(Address address, CoffRelocation relocation,
|
||||
public RelocationResult relocate(Address address, CoffRelocation relocation,
|
||||
CoffRelocationContext relocationContext)
|
||||
throws MemoryAccessException, NotFoundException, RelocationException {
|
||||
throws MemoryAccessException, RelocationException {
|
||||
|
||||
Program program = relocationContext.getProgram();
|
||||
Memory mem = program.getMemory();
|
||||
|
||||
int addend = mem.getInt(address);
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (relocation.getType()) {
|
||||
|
||||
// We are implementing these types:
|
||||
|
@ -71,7 +74,7 @@ public class X86_32_CoffRelocationHandler implements CoffRelocationHandler {
|
|||
case IMAGE_REL_I386_SECTION:
|
||||
case IMAGE_REL_I386_SECREL:
|
||||
case IMAGE_REL_I386_TOKEN: {
|
||||
break;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
// We haven't implemented these types yet:
|
||||
|
@ -80,9 +83,10 @@ public class X86_32_CoffRelocationHandler implements CoffRelocationHandler {
|
|||
case IMAGE_REL_I386_SEG12:
|
||||
case IMAGE_REL_I386_SECREL7:
|
||||
default: {
|
||||
throw new NotFoundException();
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,7 +21,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.util.exception.NotFoundException;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
|
||||
public class X86_64_CoffRelocationHandler implements CoffRelocationHandler {
|
||||
|
||||
|
@ -31,9 +32,9 @@ public class X86_64_CoffRelocationHandler implements CoffRelocationHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void relocate(Address address, CoffRelocation relocation,
|
||||
public RelocationResult relocate(Address address, CoffRelocation relocation,
|
||||
CoffRelocationContext relocationContext)
|
||||
throws MemoryAccessException, NotFoundException, RelocationException {
|
||||
throws MemoryAccessException, RelocationException {
|
||||
|
||||
Program program = relocationContext.getProgram();
|
||||
Memory mem = program.getMemory();
|
||||
|
@ -41,6 +42,8 @@ public class X86_64_CoffRelocationHandler implements CoffRelocationHandler {
|
|||
int distance = 0;
|
||||
long addend = mem.getInt(address);
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (relocation.getType()) {
|
||||
|
||||
// We are implementing these types:
|
||||
|
@ -50,6 +53,7 @@ public class X86_64_CoffRelocationHandler implements CoffRelocationHandler {
|
|||
.add(addend)
|
||||
.getOffset();
|
||||
mem.setLong(address, value);
|
||||
byteLength = 8;
|
||||
break;
|
||||
}
|
||||
case IMAGE_REL_AMD64_ADDR32: {
|
||||
|
@ -95,7 +99,7 @@ public class X86_64_CoffRelocationHandler implements CoffRelocationHandler {
|
|||
case IMAGE_REL_AMD64_SECTION:
|
||||
case IMAGE_REL_AMD64_SECREL:
|
||||
case IMAGE_REL_AMD64_TOKEN: {
|
||||
break;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
// We haven't implemented these types yet:
|
||||
|
@ -104,9 +108,10 @@ public class X86_64_CoffRelocationHandler implements CoffRelocationHandler {
|
|||
case IMAGE_REL_AMD64_PAIR:
|
||||
case IMAGE_REL_AMD64_SSPAN32:
|
||||
default: {
|
||||
throw new NotFoundException();
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
@ -35,12 +37,13 @@ public class X86_32_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_386) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
@ -48,7 +51,7 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
int type = relocation.getType();
|
||||
if (type == X86_32_ElfRelocationConstants.R_386_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
@ -64,6 +67,7 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
long offset = (int) relocationAddress.getOffset();
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
int value;
|
||||
|
||||
switch (type) {
|
||||
|
@ -114,22 +118,22 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
markAsWarning(program, relocationAddress, "R_386_TLS_DTPMOD32", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
case X86_32_ElfRelocationConstants.R_386_TLS_DTPOFF32:
|
||||
markAsWarning(program, relocationAddress, "R_386_TLS_DTPOFF32", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
case X86_32_ElfRelocationConstants.R_386_TLS_TPOFF32:
|
||||
markAsWarning(program, relocationAddress, "R_386_TLS_TPOFF32", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
case X86_32_ElfRelocationConstants.R_386_TLS_TPOFF:
|
||||
markAsWarning(program, relocationAddress, "R_386_TLS_TPOFF", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
// cases which do not use symbol value
|
||||
|
||||
|
@ -151,7 +155,7 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
// compute the relocation value (i.e., indirect)
|
||||
markAsError(program, relocationAddress, "R_386_IRELATIVE", symbolName,
|
||||
"indirect computed relocation not supported", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
case X86_32_ElfRelocationConstants.R_386_GOTPC:
|
||||
// similar to R_386_PC32 but uses .got address instead of symbol address
|
||||
|
@ -190,8 +194,8 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
default:
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,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 X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
@ -42,13 +44,12 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
return new X86_64_ElfRelocationContext(this, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
public RelocationResult relocate(ElfRelocationContext elfRelocationContext,
|
||||
ElfRelocation relocation, Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
ElfHeader elf = elfRelocationContext.getElfHeader();
|
||||
if (elf.e_machine() != ElfConstants.EM_X86_64) {
|
||||
return;
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
@ -59,7 +60,7 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
int type = relocation.getType();
|
||||
if (type == X86_64_ElfRelocationConstants.R_X86_64_NONE) {
|
||||
return;
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
@ -76,13 +77,14 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
|
||||
long offset = relocationAddress.getOffset();
|
||||
|
||||
int byteLength = 8; // most relocations affect 8-bytes (change if different)
|
||||
long value;
|
||||
|
||||
switch (type) {
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_COPY:
|
||||
markAsWarning(program, relocationAddress, "R_X86_64_COPY", symbolName, symbolIndex,
|
||||
"Runtime copy not supported", elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_64:
|
||||
value = symbolValue + addend;
|
||||
memory.setLong(relocationAddress, value);
|
||||
|
@ -96,34 +98,41 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
value = symbolValue + addend;
|
||||
value = value & 0xffff;
|
||||
memory.setShort(relocationAddress, (short) value);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_8:
|
||||
value = symbolValue + addend;
|
||||
value = value & 0xff;
|
||||
memory.setByte(relocationAddress, (byte) value);
|
||||
byteLength = 1;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_PC32:
|
||||
value = symbolValue + addend - offset;
|
||||
value = value & 0xffffffff;
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_PC16:
|
||||
value = symbolValue + addend - offset;
|
||||
value = value & 0xffff;
|
||||
memory.setShort(relocationAddress, (short) value);
|
||||
byteLength = 2;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_PC8:
|
||||
value = symbolValue + addend - offset;
|
||||
value = value & 0xff;
|
||||
memory.setByte(relocationAddress, (byte) value);
|
||||
byteLength = 1;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOT32:
|
||||
value = symbolValue + addend;
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_PLT32:
|
||||
value = symbolValue + addend - offset;
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GLOB_DAT:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_JUMP_SLOT:
|
||||
|
@ -146,11 +155,13 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
symbolValue += addend;
|
||||
value = (symbolValue & 0xffffffff);
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_SIZE32:
|
||||
value = symbolSize + addend;
|
||||
value = (value & 0xffffffff);
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
byteLength = 4;
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_SIZE64:
|
||||
value = symbolSize + addend;
|
||||
|
@ -162,22 +173,22 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
markAsWarning(program, relocationAddress, "R_X86_64_DTPMOD64", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_DTPOFF64:
|
||||
markAsWarning(program, relocationAddress, "R_X86_64_DTPOFF64", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_TPOFF64:
|
||||
markAsWarning(program, relocationAddress, "R_X86_64_TPOFF64", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_TLSDESC:
|
||||
markAsWarning(program, relocationAddress, "R_X86_64_TLSDESC", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
// cases which do not use symbol value
|
||||
|
||||
|
@ -186,6 +197,7 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
long dotgot = elfRelocationContext.getGOTValue();
|
||||
value = dotgot + addend - offset;
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
byteLength = 4;
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
markAsError(program, relocationAddress, "R_X86_64_GOTPC32", symbolName,
|
||||
|
@ -214,7 +226,7 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
else if (op == (byte) 0x8b) { // check for MOV op
|
||||
// convert to LEA op
|
||||
elfRelocationContext.getLoadHelper().addFakeRelocTableEntry(opAddr, 2);
|
||||
elfRelocationContext.getLoadHelper().addArtificialRelocTableEntry(opAddr, 2);
|
||||
memory.setByte(opAddr, (byte) 0x8d); // direct LEA op
|
||||
directValueAddr = relocationAddress;
|
||||
}
|
||||
|
@ -222,7 +234,7 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (modRM == (byte) 0x25) { // check for indirect JMP op
|
||||
// convert to direct JMP op
|
||||
// must compensate for shorter instruction by appending NOP
|
||||
elfRelocationContext.getLoadHelper().addFakeRelocTableEntry(opAddr, 2);
|
||||
elfRelocationContext.getLoadHelper().addArtificialRelocTableEntry(opAddr, 2);
|
||||
memory.setByte(opAddr, (byte) 0xe9); // direct JMP op
|
||||
memory.setByte(relocationAddress.add(3), (byte) 0x90); // append NOP
|
||||
directValueAddr = modRMAddr;
|
||||
|
@ -231,7 +243,7 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
else if (modRM == (byte) 0x15) { // check for indirect CALL instruction
|
||||
// convert to direct CALL instruction
|
||||
// use of addr32 prefix allows use of single instruction
|
||||
elfRelocationContext.getLoadHelper().addFakeRelocTableEntry(opAddr, 2);
|
||||
elfRelocationContext.getLoadHelper().addArtificialRelocTableEntry(opAddr, 2);
|
||||
memory.setByte(opAddr, (byte) 0x67); // addr32 prefix
|
||||
memory.setByte(modRMAddr, (byte) 0xe8); // direct CALL op
|
||||
directValueAddr = relocationAddress;
|
||||
|
@ -240,6 +252,7 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
if (directValueAddr != null) {
|
||||
value = symbolValue + addend - offset;
|
||||
memory.setInt(directValueAddr, (int) value);
|
||||
byteLength = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -255,6 +268,7 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
value = symbolGotAddress.getOffset() + addend - offset;
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
byteLength = 4;
|
||||
break;
|
||||
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPCREL64:
|
||||
|
@ -266,7 +280,6 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
}
|
||||
value = symbolGotAddress.getOffset() + addend - offset;
|
||||
memory.setLong(relocationAddress, value);
|
||||
break;
|
||||
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_RELATIVE:
|
||||
// word64 for LP64 and specifies word32 for ILP32,
|
||||
|
@ -301,8 +314,8 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
|||
default:
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@ package ghidra.app.util.bin.format.macho.relocation;
|
|||
|
||||
import static ghidra.app.util.bin.format.macho.relocation.X86_32_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 x86 32-bit
|
||||
|
@ -41,24 +43,25 @@ public class X86_32_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 relocAddr = relocation.getRelocationAddress();
|
||||
Address targetAddr = relocation.getTargetAddress();
|
||||
|
||||
int byteLength;
|
||||
switch (relocationInfo.getType()) {
|
||||
case GENERIC_RELOC_VANILLA:
|
||||
if (relocationInfo.isPcRelocated()) {
|
||||
write(relocation, targetAddr.subtract(relocAddr) - 4);
|
||||
byteLength = write(relocation, targetAddr.subtract(relocAddr) - 4);
|
||||
}
|
||||
else {
|
||||
write(relocation, targetAddr.getOffset());
|
||||
byteLength = write(relocation, targetAddr.getOffset());
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -68,7 +71,8 @@ public class X86_32_MachoRelocationHandler extends MachoRelocationHandler {
|
|||
case GENERIC_RELOC_LOCAL_SECTDIFF: // relocation not required (scattered)
|
||||
case GENERIC_RELOC_TLV: // not seen yet
|
||||
default:
|
||||
throw new NotFoundException("Unimplemented relocation");
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@ package ghidra.app.util.bin.format.macho.relocation;
|
|||
|
||||
import static ghidra.app.util.bin.format.macho.relocation.X86_64_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 x86 64-bit
|
||||
|
@ -40,11 +42,11 @@ public class X86_64_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();
|
||||
|
@ -52,9 +54,10 @@ public class X86_64_MachoRelocationHandler extends MachoRelocationHandler {
|
|||
Address targetAddr = relocation.getTargetAddress();
|
||||
long addend = read(relocation);
|
||||
|
||||
int byteLength;
|
||||
switch (relocationInfo.getType()) {
|
||||
case X86_64_RELOC_UNSIGNED:
|
||||
write(relocation, targetAddr.add(addend).getOffset());
|
||||
byteLength = write(relocation, targetAddr.add(addend).getOffset());
|
||||
break;
|
||||
case X86_64_RELOC_SIGNED:
|
||||
case X86_64_RELOC_BRANCH:
|
||||
|
@ -63,21 +66,24 @@ public class X86_64_MachoRelocationHandler extends MachoRelocationHandler {
|
|||
case X86_64_RELOC_SIGNED_1: // addend should already be -1
|
||||
case X86_64_RELOC_SIGNED_2: // addend should already be -2
|
||||
case X86_64_RELOC_SIGNED_4: // addend should already be -4
|
||||
write(relocation, targetAddr.add(addend).subtract(relocAddr) - 4);
|
||||
byteLength = write(relocation, targetAddr.add(addend).subtract(relocAddr) - 4);
|
||||
break;
|
||||
case X86_64_RELOC_SUBTRACTOR:
|
||||
Address targetAddrExtra = relocation.getTargetAddressExtra();
|
||||
if (addend > 0) {
|
||||
write(relocation, targetAddrExtra.add(addend).subtract(targetAddr));
|
||||
byteLength =
|
||||
write(relocation, targetAddrExtra.add(addend).subtract(targetAddr));
|
||||
}
|
||||
else {
|
||||
write(relocation, targetAddr.add(addend).subtract(targetAddrExtra));
|
||||
byteLength =
|
||||
write(relocation, targetAddr.add(addend).subtract(targetAddrExtra));
|
||||
}
|
||||
break;
|
||||
|
||||
case X86_64_RELOC_TLV: // not seen yet
|
||||
default:
|
||||
throw new NotFoundException("Unimplemented relocation");
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue