diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTableModel.java index 6607587f4c..cd81034fc7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTableModel.java @@ -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 { }; 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 { 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 { 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 { } } + private static class RelocationStatusColumn extends + AbstractProgramBasedDynamicTableColumn { + + @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 { @@ -182,12 +223,12 @@ class RelocationTableModel extends AddressBasedTableModel { } } - private static class RelocationBytesColumn extends + private static class RelocationOriginalBytesColumn extends AbstractProgramBasedDynamicTableColumn { @Override public String getColumnName() { - return RELOCATION_BYTES; + return RELOCATION_ORIGINAL_BYTES; } @Override @@ -195,23 +236,33 @@ class RelocationTableModel extends AddressBasedTableModel { ServiceProvider serviceProvider) throws IllegalArgumentException { return packBytes(rowObject.relocation.getBytes()); } + } - private String packBytes(byte[] bytes) { - if (bytes == null) { - return ""; + private static class RelocationCurrentBytesColumn extends + AbstractProgramBasedDynamicTableColumn { + + @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); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/relocation/CoffRelocationHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/relocation/CoffRelocationHandler.java index d00f2b18f2..f2313224d2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/relocation/CoffRelocationHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/relocation/CoffRelocationHandler.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java index 4c6764e399..1a182a78be 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java @@ -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); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfLoadHelper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfLoadHelper.java index babdffccca..2946451e28 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfLoadHelper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfLoadHelper.java @@ -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); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationContext.java index 72f4f7cb05..e8e362d73a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationContext.java @@ -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; } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java index 039b27764a..a0c3fbbb37 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java @@ -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; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java index ea7547f437..c667d5e3bb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java @@ -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); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo1.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo1.java index 499e2791d3..0054eb04ff 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo1.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo1.java @@ -138,8 +138,6 @@ public class DyldCacheSlideInfo1 extends DyldCacheSlideInfoCommon { List
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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo2.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo2.java index 63eba1a809..76fd7a3064 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo2.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo2.java @@ -212,8 +212,6 @@ public class DyldCacheSlideInfo2 extends DyldCacheSlideInfoCommon { Memory memory = program.getMemory(); List
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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo3.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo3.java index 3e71b99de3..ada966a300 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo3.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo3.java @@ -172,8 +172,6 @@ public class DyldCacheSlideInfo3 extends DyldCacheSlideInfoCommon { List
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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo4.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo4.java index 1c21b38549..82ac37ec26 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo4.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfo4.java @@ -225,8 +225,6 @@ public class DyldCacheSlideInfo4 extends DyldCacheSlideInfoCommon { List
unchainedLocList = new ArrayList
(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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfoCommon.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfoCommon.java index bc6edeb923..ef692a6296 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfoCommon.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheSlideInfoCommon.java @@ -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); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldChainedPtr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldChainedPtr.java index c22b33cb49..0b757a2251 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldChainedPtr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldChainedPtr.java @@ -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 mach-o/fixup-chains.h @@ -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) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocation.java index a7a439610e..e3f512e9dc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocation.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocation.java @@ -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"); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocationHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocationHandler.java index d705eba0c7..ba7d60776b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocationHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocationHandler.java @@ -15,13 +15,15 @@ */ package ghidra.app.util.bin.format.macho.relocation; +import ghidra.app.util.bin.format.RelocationException; import ghidra.app.util.bin.format.macho.MachHeader; import ghidra.app.util.bin.format.macho.RelocationInfo; import ghidra.program.model.address.Address; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.reloc.Relocation.Status; +import ghidra.program.model.reloc.RelocationResult; import ghidra.util.classfinder.ExtensionPoint; -import ghidra.util.exception.NotFoundException; /** * An abstract class used to perform Mach-O relocations. Classes should extend this class to @@ -51,13 +53,17 @@ abstract public class MachoRelocationHandler implements ExtensionPoint { /** * Performs a relocation - + * @param relocation The relocation to perform + * @return applied relocation result * @throws MemoryAccessException If there is a problem accessing memory during the relocation - * @throws NotFoundException If this handler didn't find a way to perform the relocation + * @throws RelocationException if supported relocation encountered an error during processing. + * This exception should be thrown in place of returning {@link RelocationResult#FAILURE} or + * a status of {@link Status#FAILURE} which will facilitate a failure reason via + * {@link RelocationException#getMessage()}. */ - abstract public void relocate(MachoRelocation relocation) - throws MemoryAccessException, NotFoundException; + abstract public RelocationResult relocate(MachoRelocation relocation) + throws MemoryAccessException, RelocationException; /** * Reads bytes at the given address. The size of the read is determined by the length of the @@ -90,23 +96,25 @@ abstract public class MachoRelocationHandler implements ExtensionPoint { * * @param relocation The relocation to write * @param value The value to write + * @return number of bytes written * @throws MemoryAccessException If there is a problem accessing memory during the write */ - public static void write(MachoRelocation relocation, long value) throws MemoryAccessException { + public static int write(MachoRelocation relocation, long value) throws MemoryAccessException { Memory mem = relocation.getProgram().getMemory(); - int len = relocation.getRelocationInfo().getLength(); Address addr = relocation.getRelocationAddress(); - if (len == 3) { - mem.setLong(addr, value); - } - else if (len == 2) { - mem.setInt(addr, (int) value); - } - else if (len == 1) { - mem.setShort(addr, (short) value); - } - else { - mem.setByte(addr, (byte) value); + switch (relocation.getRelocationInfo().getLength()) { + case 3: + mem.setLong(addr, value); + return 8; + case 2: + mem.setInt(addr, (int) value); + return 4; + case 1: + mem.setShort(addr, (short) value); + return 2; + default: + mem.setByte(addr, (byte) value); + return 1; } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pef/RelocationState.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pef/RelocationState.java index 769bf4a03c..bca794742e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pef/RelocationState.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pef/RelocationState.java @@ -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) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java index 118ad2634e..a46cb497cf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java @@ -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() : ""); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java index dc5dab03f8..3df55d37ce 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java @@ -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 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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java index 4b84f81733..24dac9bc6e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java @@ -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); + } } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java index a285eba709..b7e0585f74 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java @@ -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); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java index cedba7491d..a0a38f7e53 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java @@ -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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java index 4b394c3015..3103998a29 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java @@ -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); } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java index 9550659000..bd92a7c0d4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java @@ -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); } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/RelocationTableXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/RelocationTableXmlMgr.java index 90def5dcea..910aa1eefa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/RelocationTableXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/RelocationTableXmlMgr.java @@ -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; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java b/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java index f30c754890..9d8ee3b36c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java @@ -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) { diff --git a/Ghidra/Features/Base/src/main/resources/PROGRAM.DTD b/Ghidra/Features/Base/src/main/resources/PROGRAM.DTD index 99f1aa39be..3d4449ff62 100644 --- a/Ghidra/Features/Base/src/main/resources/PROGRAM.DTD +++ b/Ghidra/Features/Base/src/main/resources/PROGRAM.DTD @@ -160,8 +160,12 @@ + + + + - + diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/dex/analyzer/DexHeaderFormatMarkup.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/dex/analyzer/DexHeaderFormatMarkup.java index 18e1e7cbf6..c8ccfac3e7 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/dex/analyzer/DexHeaderFormatMarkup.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/dex/analyzer/DexHeaderFormatMarkup.java @@ -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()); diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/dex/format/StringDataItem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/dex/format/StringDataItem.java index 2307ce20f9..8d24fe5da4 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/dex/format/StringDataItem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/dex/format/StringDataItem.java @@ -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; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java index d10cf4fdba..80cfeb8140 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java @@ -107,9 +107,11 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM * TypeDefSettingsDefinition. Added DataTypeManager versioning * support. Added support for auto-named TypeDef datatypes. * Transitioned string data translation storage to use address-based - * property map (StringTranslations). + * property map (StringTranslations). + * 19-Jan-2023 - version 26 Improved relocation data records to incorporate status and + * byte-length when original FileBytes should be used. */ - static final int DB_VERSION = 25; + static final int DB_VERSION = 26; /** * UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the @@ -129,6 +131,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM public static final int EXTERNAL_FUNCTIONS_ADDED_VERSION = 17; public static final int COMPOUND_VARIABLE_STORAGE_ADDED_VERSION = 18; public static final int AUTO_PARAMETERS_ADDED_VERSION = 19; + public static final int RELOCATION_STATUS_ADDED_VERSION = 26; private static final String DATA_MAP_TABLE_NAME = "Program"; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapter.java index a75d8bd4d6..327578e6bb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapter.java @@ -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 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. + *

+ * 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 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; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterNoTable.java index 486e2600e1..158a587619 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterNoTable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterNoTable.java @@ -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(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV1.java index f67b922620..18957a7e4e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV1.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV1.java @@ -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; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV2.java index fbb9074e2f..2882b86c1f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV2.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV2.java @@ -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)); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV3.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV3.java index 32950ca69e..e1097c4358 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV3.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV3.java @@ -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)); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV4.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV4.java index 3ef8a1fe36..ac8b14886b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV4.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV4.java @@ -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)); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV5.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV5.java index 3124c44fef..97faf4b941 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV5.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV5.java @@ -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; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV6.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV6.java new file mode 100644 index 0000000000..683719b781 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV6.java @@ -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. + *
+ * 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); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationManager.java index 8b2f8baca1..95f8535ffa 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationManager.java @@ -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 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)); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/Relocation.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/Relocation.java index a52bb5d87f..0892459f1e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/Relocation.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/Relocation.java @@ -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. * diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationResult.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationResult.java new file mode 100644 index 0000000000..579edb7d42 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationResult.java @@ -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. + *
+ * 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); + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationTable.java index 128948ea99..b1a704038c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationTable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationTable.java @@ -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. diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java index aff6978ab7..62c7cb6e7c 100644 --- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java @@ -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; } /** diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/macho/relocation/AARCH64_MachoRelocationHandler.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/macho/relocation/AARCH64_MachoRelocationHandler.java index d0489dc699..cbed3c3902 100644 --- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/macho/relocation/AARCH64_MachoRelocationHandler.java +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/macho/relocation/AARCH64_MachoRelocationHandler.java @@ -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); } /** diff --git a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java index 84fabf37a1..bb06c8dea2 100644 --- a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java +++ b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java @@ -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) { diff --git a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/macho/relocation/ARM_MachoRelocationHandler.java b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/macho/relocation/ARM_MachoRelocationHandler.java index 005c3c1191..b87645d449 100644 --- a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/macho/relocation/ARM_MachoRelocationHandler.java +++ b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/macho/relocation/ARM_MachoRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR32_ElfRelocationHandler.java b/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR32_ElfRelocationHandler.java index 0ea8891d41..9e3859e22e 100644 --- a/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR32_ElfRelocationHandler.java +++ b/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR32_ElfRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR8_ElfRelocationHandler.java b/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR8_ElfRelocationHandler.java index a706151e2f..3d9379975b 100644 --- a/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR8_ElfRelocationHandler.java +++ b/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR8_ElfRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/extend/MIPS_ElfExtension.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/extend/MIPS_ElfExtension.java index 755852570e..57e5b64603 100644 --- a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/extend/MIPS_ElfExtension.java +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/extend/MIPS_ElfExtension.java @@ -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); } } diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationContext.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationContext.java new file mode 100644 index 0000000000..d59589e956 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationContext.java @@ -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 hi16list = new LinkedList<>(); + private LinkedList got16list = new LinkedList<>(); + + private AddressRange sectionGotLimits; + private Address sectionGotAddress; + private Address lastSectionGotEntryAddress; + private Address nextSectionGotEntryAddress; + + private Map gotMap; + + boolean useSavedAddend = false; + boolean savedAddendHasError = false; + long savedAddend; + + Address lastSymbolAddr; + + MIPS_ElfRelocationContext(MIPS_ElfRelocationHandler handler, ElfLoadHelper loadHelper, + Map 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 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 iterateGot16() { + return got16list.iterator(); + } + + /** + * Add HI16 relocation for deferred processing + * @param hi16reloc HI16 relocation + */ + void addGOT16Relocation(MIPS_DeferredRelocation got16reloc) { + got16list.add(got16reloc); + } +} diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java index 6099fb82ef..6543e6e528 100644 --- a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java @@ -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; } - /** - * 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. - */ - private static class MIPS_ElfRelocationContext extends ElfRelocationContext { - - private LinkedList hi16list = new LinkedList<>(); - private LinkedList got16list = new LinkedList<>(); - - private AddressRange sectionGotLimits; - private Address sectionGotAddress; - private Address lastSectionGotEntryAddress; - private Address nextSectionGotEntryAddress; - - private Map gotMap; - - private boolean useSavedAddend = false; - private boolean savedAddendHasError = false; - private long savedAddend; - - private Address lastSymbolAddr; - - MIPS_ElfRelocationContext(MIPS_ElfRelocationHandler handler, ElfLoadHelper loadHelper, - Map 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 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 iterateGot16() { - return got16list.iterator(); - } - - /** - * Add HI16 relocation for deferred processing - * @param hi16reloc HI16 relocation - */ - void addGOT16Relocation(MIPS_DeferredRelocation got16reloc) { - got16list.add(got16reloc); - } - } - /** * MIPS_DeferredRelocation 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; diff --git a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationHandler.java b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationHandler.java index 9bb341cc3d..212facf1cf 100644 --- a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationHandler.java +++ b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java index dedd835195..c92d960bf9 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java @@ -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) { diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java index abf38aa08b..97534f06e9 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java @@ -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); } /** diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java index 5acbda3579..603d7d21f2 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java @@ -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); } /** diff --git a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java index fd143686fe..b0c5404e2a 100644 --- a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java +++ b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java @@ -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, - "TODO, needs support ", elfRelocationContext.getLog()); - break; + 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_JUMP_SLOT: - // Runtime relocation word32,64 = S ;handled by PLT unless LD_BIND_NOW - if (is32) { - value32 = (int)(symbolValue); + 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()); + 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); + 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, - "TODO, needs support ", elfRelocationContext.getLog()); - break; - - 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()); - 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, - "TODO, needs support ", elfRelocationContext.getLog()); - 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, - "TODO, needs support ", elfRelocationContext.getLog()); - 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, - "TODO, needs support ", elfRelocationContext.getLog()); - break; - - 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()); - break; - - case RISCV_ElfRelocationConstants.R_RISCV_BRANCH: - // PC-relative branch (SB-Type) - markAsWarning(program, relocationAddress, "R_RISCV_BRANCH", 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_JAL: - // PC-relative jump (UJ-Type) - markAsWarning(program, relocationAddress, "R_RISCV_JAL", 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_CALL: - // PC-relative call MACRO call,tail (auipc+jalr pair) - markAsWarning(program, relocationAddress, "R_RISCV_CALL", 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_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_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_GOT_HI20: - // PC-relative GOT reference MACRO la - markAsWarning(program, relocationAddress, "R_RISCV_GOT_HI20", 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_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_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_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_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_PCREL_HI20: - // PC-relative reference %pcrel_hi(symbol) (U-Type) - markAsWarning(program, relocationAddress, "R_RISCV_PCREL_HI20", 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_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_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_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_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_HI20: - // Absolute address %hi(symbol) (U-Type) - markAsWarning(program, relocationAddress, "R_RISCV_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_LO12_I: - // Absolute address %lo(symbol) (I-Type) - markAsWarning(program, relocationAddress, "R_RISCV_LO12_I", 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_LO12_S: - // Absolute address %lo(symbol) (S-Type) - markAsWarning(program, relocationAddress, "R_RISCV_LO12_S", 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_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_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_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_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_TPREL_LO12_S: - // TLS LE thread offset %tprel_lo(symbol) (S-Type) - markAsWarning(program, relocationAddress, "R_RISCV_TPREL_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_TPREL_ADD: - // TLS LE thread usage %tprel_add(symbol) - markAsWarning(program, relocationAddress, "R_RISCV_TPREL_ADD", 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_ADD8: - // 8-bit label addition word8 = old + S + A - markAsWarning(program, relocationAddress, "R_RISCV_ADD8", symbolName, symbolIndex, + case RISCV_ElfRelocationConstants.R_RISCV_SET8: + // Local label subtraction + markAsWarning(program, relocationAddress, "R_RISCV_SET8", symbolName, symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); - value8 = memory.getByte(relocationAddress); - value8 += (byte)symbolValue; - value8 += (byte)addend; - memory.setByte(relocationAddress, value8); - break; + return RelocationResult.UNSUPPORTED; - case RISCV_ElfRelocationConstants.R_RISCV_ADD16: - // 16-bit label addition word16 = old + S + A - markAsWarning(program, relocationAddress, "R_RISCV_ADD16", symbolName, symbolIndex, + case RISCV_ElfRelocationConstants.R_RISCV_SET16: + // Local label subtraction + markAsWarning(program, relocationAddress, "R_RISCV_SET16", symbolName, symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); - value16 = memory.getShort(relocationAddress); - value16 += (short)symbolValue; - value16 += (short)addend; - memory.setShort(relocationAddress, value16); - break; + return RelocationResult.UNSUPPORTED; - case RISCV_ElfRelocationConstants.R_RISCV_ADD32: - // 32-bit label addition word32 = old + S + A - markAsWarning(program, relocationAddress, "R_RISCV_ADD32", symbolName, symbolIndex, + case RISCV_ElfRelocationConstants.R_RISCV_SET32: + // Local label subtraction + markAsWarning(program, relocationAddress, "R_RISCV_SET32", symbolName, symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); - value32 = memory.getInt(relocationAddress); - value32 += (int)symbolValue; - value32 += (int)addend; - memory.setInt(relocationAddress, value32); - break; + return RelocationResult.UNSUPPORTED; - case RISCV_ElfRelocationConstants.R_RISCV_ADD64: - // 64-bit label addition word64 = old + S + A - markAsWarning(program, relocationAddress, "R_RISCV_ADD64", 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()); - value64 = memory.getLong(relocationAddress); - value64 += symbolValue; - value64 += addend; - memory.setLong(relocationAddress, value64); - break; + return RelocationResult.UNSUPPORTED; - 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; - - } + 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); } } diff --git a/Ghidra/Processors/Sparc/src/main/java/ghidra/app/util/bin/format/elf/relocation/SPARC_ElfRelocationHandler.java b/Ghidra/Processors/Sparc/src/main/java/ghidra/app/util/bin/format/elf/relocation/SPARC_ElfRelocationHandler.java index 3f308bb307..fd888c815e 100644 --- a/Ghidra/Processors/Sparc/src/main/java/ghidra/app/util/bin/format/elf/relocation/SPARC_ElfRelocationHandler.java +++ b/Ghidra/Processors/Sparc/src/main/java/ghidra/app/util/bin/format/elf/relocation/SPARC_ElfRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/util/bin/format/elf/relocation/SH_ElfRelocationHandler.java b/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/util/bin/format/elf/relocation/SH_ElfRelocationHandler.java index 23f29521bb..5aca0477cc 100644 --- a/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/util/bin/format/elf/relocation/SH_ElfRelocationHandler.java +++ b/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/util/bin/format/elf/relocation/SH_ElfRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/coff/relocation/X86_32_CoffRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/coff/relocation/X86_32_CoffRelocationHandler.java index c45687b182..8f1251ec52 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/coff/relocation/X86_32_CoffRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/coff/relocation/X86_32_CoffRelocationHandler.java @@ -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); } /** diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/coff/relocation/X86_64_CoffRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/coff/relocation/X86_64_CoffRelocationHandler.java index 891d8b371f..4cbf07a99d 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/coff/relocation/X86_64_CoffRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/coff/relocation/X86_64_CoffRelocationHandler.java @@ -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); } /** diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java index 7c0943906b..ffa747814b 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java index 862dbbdbb0..9b9244a226 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/macho/relocation/X86_32_MachoRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/macho/relocation/X86_32_MachoRelocationHandler.java index 49bf72d6c0..11e637b141 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/macho/relocation/X86_32_MachoRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/macho/relocation/X86_32_MachoRelocationHandler.java @@ -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); } } diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/macho/relocation/X86_64_MachoRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/macho/relocation/X86_64_MachoRelocationHandler.java index e3b8681d0b..9debe742cb 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/macho/relocation/X86_64_MachoRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/macho/relocation/X86_64_MachoRelocationHandler.java @@ -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); } }