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:
ghidra1 2023-01-17 15:04:22 -05:00
parent f022b9a4d5
commit 5b433f35ca
63 changed files with 2146 additions and 1147 deletions

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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;
}
/**

View file

@ -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;

View file

@ -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);
}
/**

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
/**

View file

@ -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)

View file

@ -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");
}
/**

View file

@ -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;
}
}
}

View file

@ -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) {

View file

@ -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>");
}
}

View file

@ -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);

View file

@ -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);
}
}
/**

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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) {

View file

@ -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>

View file

@ -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());

View file

@ -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;
}

View file

@ -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";

View file

@ -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;

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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));

View file

@ -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));

View file

@ -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));

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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));
}

View file

@ -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.
*

View file

@ -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);
}

View file

@ -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.

View file

@ -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;
}
/**

View file

@ -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);
}
/**

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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);
}
/**

View file

@ -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);
}
/**

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
/**

View file

@ -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);
}
/**

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}