From 021fbf8025c29f28ec4a07ddd05ff0c5d86fe715 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Thu, 29 Oct 2020 17:29:06 -0400 Subject: [PATCH] GP-348 Added ELF RELR relocation support --- .../cmd/formats/ElfBinaryAnalysisCommand.java | 9 +- .../util/bin/format/elf/ElfDynamicType.java | 17 +-- .../app/util/bin/format/elf/ElfHeader.java | 23 ++-- .../util/bin/format/elf/ElfRelocation.java | 31 +++-- .../bin/format/elf/ElfRelocationTable.java | 69 ++++++++++- .../elf/ElfRelrRelocationTableDataType.java | 117 ++++++++++++++++++ .../elf/relocation/ElfRelocationContext.java | 11 +- .../elf/relocation/ElfRelocationHandler.java | 24 ++++ .../app/util/opinion/ElfProgramBuilder.java | 35 +++++- .../model/data/FactoryStructureDataType.java | 19 ++- .../AARCH64_ElfRelocationHandler.java | 5 + .../X86_32_ElfRelocationHandler.java | 5 + .../X86_64_ElfRelocationHandler.java | 5 + 13 files changed, 334 insertions(+), 36 deletions(-) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelrRelocationTableDataType.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/formats/ElfBinaryAnalysisCommand.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/formats/ElfBinaryAnalysisCommand.java index 829e67473c..7745191a11 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/formats/ElfBinaryAnalysisCommand.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/formats/ElfBinaryAnalysisCommand.java @@ -414,7 +414,14 @@ public class ElfBinaryAnalysisCommand extends FlatProgramAPI // elf.getSection(relocationTable.getFileOffset()); // may be null Address relocationTableAddress = addr(relocationTable.getFileOffset()); try { - createData(relocationTableAddress, relocationTable.toDataType()); + DataType dataType = relocationTable.toDataType(); + if (dataType != null) { + createData(relocationTableAddress, dataType); + } + else { + listing.setComment(relocationTableAddress, CodeUnit.PRE_COMMENT, + "ELF Relocation Table (markup not yet supported)"); + } } catch (Exception e) { messages.appendMsg( diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDynamicType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDynamicType.java index 024fd03057..4d09f80df5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDynamicType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDynamicType.java @@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.elf; import java.util.HashMap; import java.util.Map; +import ghidra.util.Msg; import ghidra.util.StringUtilities; import ghidra.util.exception.DuplicateNameException; @@ -96,11 +97,11 @@ public class ElfDynamicType { // Experimental RELR relocation support // - see proposal at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg - public static ElfDynamicType DT_RELRSZ = addDefaultDynamicType(35, "DT_RELSZ", + public static ElfDynamicType DT_RELRSZ = addDefaultDynamicType(35, "DT_RELRSZ", "Total size of Relr relocs", ElfDynamicValueType.VALUE); - public static ElfDynamicType DT_RELR = addDefaultDynamicType(36, "DT_RELR", - "Address of Relr relocs", ElfDynamicValueType.ADDRESS); - public static ElfDynamicType DT_RELRENT = addDefaultDynamicType(37, "DT_RELSZ", + public static ElfDynamicType DT_RELR = + addDefaultDynamicType(36, "DT_RELR", "Address of Relr relocs", ElfDynamicValueType.ADDRESS); + public static ElfDynamicType DT_RELRENT = addDefaultDynamicType(37, "DT_RELRENT", "Size of Relr relocation entry", ElfDynamicValueType.VALUE); public static final int DF_ORIGIN = 0x1; // $ORIGIN processing required @@ -131,9 +132,9 @@ public class ElfDynamicType { public static ElfDynamicType DT_ANDROID_RELR = addDefaultDynamicType(0x6FFFE000, "DT_ANDROID_RELR", "Address of Relr relocs", ElfDynamicValueType.ADDRESS); public static ElfDynamicType DT_ANDROID_RELRSZ = addDefaultDynamicType(0x6FFFE001, - "DT_ANDROID_RELSZ", "Total size of Relr relocs", ElfDynamicValueType.VALUE); + "DT_ANDROID_RELRSZ", "Total size of Relr relocs", ElfDynamicValueType.VALUE); public static ElfDynamicType DT_ANDROID_RELRENT = addDefaultDynamicType(0x6FFFE003, - "DT_ANDROID_RELSZ", "Size of Relr relocation entry", ElfDynamicValueType.VALUE); + "DT_ANDROID_RELRENT", "Size of Relr relocation entry", ElfDynamicValueType.VALUE); // Value Range (??): 0x6ffffd00 - 0x6ffffdff @@ -233,7 +234,9 @@ public class ElfDynamicType { return type; } catch (DuplicateNameException e) { - throw new RuntimeException("ElfDynamicType initialization error", e); + // Make sure error is properly logged during static initialization + Msg.error(ElfDynamicType.class, "ElfDynamicType initialization error", e); + throw new RuntimeException(e); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java index 72cb9c1009..96f8b7091a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java @@ -372,12 +372,11 @@ public class ElfHeader implements StructConverter, Writeable { parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELA, null, ElfDynamicType.DT_ANDROID_RELASZ, true); - // TODO: -// parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_RELR, -// ElfDynamicType.DT_RELRENT, ElfDynamicType.DT_RELRSZ, false); -// -// parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELR, -// ElfDynamicType.DT_ANDROID_RELRENT, ElfDynamicType.DT_ANDROID_RELRSZ, false); + parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_RELR, + ElfDynamicType.DT_RELRENT, ElfDynamicType.DT_RELRSZ, false); + + parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELR, + ElfDynamicType.DT_ANDROID_RELRENT, ElfDynamicType.DT_ANDROID_RELRSZ, false); parseJMPRelocTable(relocationTableList); @@ -397,8 +396,10 @@ public class ElfHeader implements StructConverter, Writeable { int sectionHeaderType = section.getType(); if (sectionHeaderType == ElfSectionHeaderConstants.SHT_REL || sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA || + sectionHeaderType == ElfSectionHeaderConstants.SHT_RELR || sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL || - sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) { + sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA || + sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELR) { for (ElfRelocationTable relocTable : relocationTableList) { if (relocTable.getFileOffset() == section.getOffset()) { @@ -447,6 +448,10 @@ public class ElfHeader implements StructConverter, Writeable { sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) { format = TableFormat.ANDROID; } + else if (sectionHeaderType == ElfSectionHeaderConstants.SHT_RELR || + sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELR) { + format = TableFormat.RELR; + } ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader, this, section, section.getOffset(), section.getAddress(), section.getSize(), @@ -534,6 +539,10 @@ public class ElfHeader implements StructConverter, Writeable { relocTableAddrType == ElfDynamicType.DT_ANDROID_RELA) { format = TableFormat.ANDROID; } + else if (relocTableAddrType == ElfDynamicType.DT_RELR || + relocTableAddrType == ElfDynamicType.DT_ANDROID_RELR) { + format = TableFormat.RELR; + } ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader, this, null, relocTableOffset, relocTableAddr, tableSize, tableEntrySize, diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocation.java index 634b9d7c49..5bd545a753 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocation.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocation.java @@ -22,6 +22,8 @@ import ghidra.app.util.bin.ByteArrayConverter; import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter; +import ghidra.app.util.bin.format.elf.relocation.ElfRelocationContext; +import ghidra.app.util.bin.format.elf.relocation.ElfRelocationHandler; import ghidra.program.model.data.*; import ghidra.util.Conv; import ghidra.util.DataConverter; @@ -63,13 +65,10 @@ import ghidra.util.exception.AssertException; * } Elf64_Rela; * * RELR entry (see SHT_RELR, DT_RELR): - * NOTE: Relocation type is implied as Relative with addend stored at relocation offset. - * The specific relocation type wil need to be obtained from processor extension. + * NOTE: Relocation type is data relative and must be specified by appropriate relocation handler + * (see {@link ElfRelocationHandler#getRelrRelocationType()}) since it is not contained within the + * relocation table which only specifies r_offset for each entry. * - * typedef Elf32_Word Elf32_Relr; - * - * typedef Elf64_Xword Elf64_Relr; - * * */ public class ElfRelocation implements ByteArrayConverter, StructConverter { @@ -269,6 +268,8 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter { /** * Returns the symbol index where the relocation must be made. + * A value of 0 is generally returned when no symbol is relavent + * to the relocation. * @return the symbol index */ public int getSymbolIndex() { @@ -277,13 +278,28 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter { /** * The type of relocation to apply. - * NOTE: Relocation types are processor-specific. + * NOTE 1: Relocation types are processor-specific (see {@link ElfRelocationHandler}). + * NOTE 2: A type of 0 is returned by default for RELR relocations and must be updated + * during relocation processing (see {@link #setType(long)}). The appropriate RELR + * relocation type can be obtained from the appropriate + * {@link ElfRelocationHandler#getRelrRelocationType()} or + * {@link ElfRelocationContext#getRelrRelocationType()} if available. * @return type of relocation to apply */ public int getType() { return (int) (is32bit ? (r_info & Conv.BYTE_MASK) : (r_info & Conv.INT_MASK)); } + /** + * Set the relocation type associated with this relocation. + * Updating the relocation type is required for RELR relocations. + * @param type relocation type to be applied + */ + public void setType(long type) { + long mask = is32bit ? Conv.BYTE_MASK : Conv.INT_MASK; + r_info = (r_info & ~mask) + (type & mask); + } + /** * Returns the r_info relocation entry field value * @return r_info value @@ -372,4 +388,5 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter { } return is32bit ? 8 : 16; } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocationTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocationTable.java index 9c3c2dc2ef..5f80da427b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocationTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocationTable.java @@ -34,7 +34,7 @@ import ghidra.util.Msg; public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { public enum TableFormat { - DEFAULT, ANDROID; + DEFAULT, ANDROID, RELR; } private TableFormat format; @@ -111,7 +111,10 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { reader.setPointerIndex(fileOffset); List relocList; - if (format == TableFormat.ANDROID) { + if (format == TableFormat.RELR) { + relocList = parseRelrRelocations(reader); + } + else if (format == TableFormat.ANDROID) { relocList = parseAndroidRelocations(reader); } else { @@ -139,6 +142,57 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { return relocations; } + private long readNextRelrEntry(FactoryBundledWithBinaryReader reader) throws IOException { + return entrySize == 8 ? reader.readNextLong() : reader.readNextUnsignedInt(); + } + + private long addRelrEntry(long offset, List relocList) { + relocList.add(ElfRelocation.createElfRelocation(factory, elfHeader, relocList.size(), + addendTypeReloc, offset, 0, 0)); + return offset + entrySize; + } + + private long addRelrEntries(long baseOffset, long entry, List relocList) { + + long offset = baseOffset; + while (entry != 0) { + entry >>>= 1; + if ((entry & 1) != 0) { + relocList.add(ElfRelocation.createElfRelocation(factory, elfHeader, + relocList.size(), addendTypeReloc, offset, 0, 0)); + } + offset += entrySize; + } + long nBits = (entrySize * 8) - 1; + return baseOffset + (nBits * entrySize); + } + + private List parseRelrRelocations(FactoryBundledWithBinaryReader reader) + throws IOException { + + // NOTE: Current implementation supports an entrySize of 8 or 4. This could be + // made more flexable if needed (applies to ElfRelrRelocationTableDataType as well) + + List relocList = new ArrayList<>(); + long remaining = length; // limit to number of bytes specified for RELR table + + long offset = readNextRelrEntry(reader); + offset = addRelrEntry(offset, relocList); + remaining -= entrySize; + + while (remaining > 0) { + long nextValue = readNextRelrEntry(reader); + if ((nextValue & 1) == 1) { + offset = addRelrEntries(offset, nextValue, relocList); + } + else { + offset = addRelrEntry(nextValue, relocList); + } + remaining -= entrySize; + } + return relocList; + } + private List parseAndroidRelocations(FactoryBundledWithBinaryReader reader) throws IOException { @@ -288,6 +342,10 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { return relocTableSection; } + public boolean isRelrTable() { + return format == TableFormat.RELR; + } + @Override public long getFileOffset() { return fileOffset; @@ -300,7 +358,12 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { @Override public DataType toDataType() { - if (format == TableFormat.ANDROID) { + if (format == TableFormat.RELR) { + String relrStructureName = "Elf_RelrRelocationTable_" + Long.toHexString(addrOffset); + return new ElfRelrRelocationTableDataType(relrStructureName, (int) length, + (int) entrySize); + } + else if (format == TableFormat.ANDROID) { return new AndroidElfRelocationTableDataType(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelrRelocationTableDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelrRelocationTableDataType.java new file mode 100644 index 0000000000..1f9c2bf141 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelrRelocationTableDataType.java @@ -0,0 +1,117 @@ +/* ### + * 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; + +import ghidra.program.model.data.*; +import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.util.exception.DuplicateNameException; + +/** + * ElfRelrRelocationTableDataType is a Factory datatype which defines a markup + * structure corresponding to a specified ELF REL relocation table. The REL entry size and + * total length in bytes is required when interpreting a RELR table. + */ +class ElfRelrRelocationTableDataType extends FactoryStructureDataType { + + private int length; + private int entrySize; + + /** + * Constructor + * @param structName structure name for resulting structure + * @param length total length of RELR table in bytes + * @param entrySize RELR entry size. This size also generally corresponds to the + * size if a stored pointer. + */ + ElfRelrRelocationTableDataType(String structName, int length, int entrySize) { + this(structName, length, entrySize, null); + } + + private ElfRelrRelocationTableDataType(String structName, int length, int entrySize, + DataTypeManager dtm) { + super(structName, dtm); + this.length = length; + this.entrySize = entrySize; + } + + @Override + public DataType clone(DataTypeManager dtm) { + if (dtm == dataMgr) { + return this; + } + return new ElfRelrRelocationTableDataType(getName(), length, entrySize, dtm); + } + + private long readNextRelrEntry(MemBuffer buf, int bufOffset) throws MemoryAccessException { + return entrySize == 8 ? buf.getLong(bufOffset) : buf.getUnsignedInt(bufOffset); + } + + @Override + protected void populateDynamicStructure(MemBuffer buf, Structure struct) { + + DataType entryDataType = entrySize == 8 ? QWordDataType.dataType : DWordDataType.dataType; + + int bufOffset = 0; + int remaining = length; // limit to number of bytes specified for RELR table + int index = 0; // relr base index + + struct.add(entryDataType, "r_relr_base_" + (++index), null); + bufOffset += entrySize; + remaining -= entrySize; + + int bitMaskCount = 0; + + try { + while (remaining > 0) { + long nextValue = readNextRelrEntry(buf, bufOffset); + if ((nextValue & 1) == 1) { + ++bitMaskCount; + } + else { + if (bitMaskCount != 0) { + DataType maskArray = new ArrayDataType(entryDataType, bitMaskCount, entrySize); + struct.add(maskArray, "r_relr_bits_" + index, null); + bitMaskCount = 0; + } + struct.add(entryDataType, "r_relr_base_" + (++index), null); + } + bufOffset += entrySize; + remaining -= entrySize; + } + + if (bitMaskCount != 0) { + DataType maskArray = new ArrayDataType(entryDataType, bitMaskCount, entrySize); + struct.add(maskArray, "r_relr_bits_" + index, null); + } + } + catch (MemoryAccessException | IllegalArgumentException e) { + // ignore + } + } + + @Override + protected Structure setCategoryPath(Structure struct, MemBuffer buf) { + try { + struct.setCategoryPath(new CategoryPath("/ELF")); + } + catch (DuplicateNameException e) { + // ignore - will not happen + } + return struct; + } + +} 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 e11895122d..7de8d26b0b 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 @@ -92,6 +92,15 @@ public class ElfRelocationContext { } } + /** + * Get the RELR relocation type associated with the underlying + * relocation handler. + * @return RELR relocation type or 0 if not supported + */ + public long getRelrRelocationType() { + return handler != null ? handler.getRelrRelocationType() : 0; + } + private void handleUnsupportedTLSRelocation(ElfRelocation relocation, Address relocationAddress) { long symbolIndex = relocation.getSymbolIndex(); @@ -116,7 +125,7 @@ public class ElfRelocationContext { * @param loadHelper Elf load helper * @param relocationTable Elf relocation table * @param symbolMap Elf symbol placement map - * @return relocation context + * @return relocation context or null */ public static ElfRelocationContext getRelocationContext(ElfLoadHelper loadHelper, ElfRelocationTable relocationTable, Map symbolMap) { 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 3e03746f5c..2f0e0443e1 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 @@ -33,12 +33,24 @@ abstract public class ElfRelocationHandler implements ExtensionPoint { abstract public boolean canRelocate(ElfHeader elf); + /** + * Get the architecture-specific relative relocation type + * which should be applied to RELR relocations. The + * default implementation returns 0 which indicates + * RELR is unsupported. + * @return RELR relocation type + */ + public int getRelrRelocationType() { + return 0; + } + /** * Relocation context for a specific Elf image and relocation table. The relocation context * is used to process relocations and manage any data required to process relocations. * @param loadHelper Elf load helper * @param relocationTable Elf relocation table * @param symbolMap Elf symbol placement map + * @return relocation context or null if unsupported */ public ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper, ElfRelocationTable relocationTable, Map symbolMap) { @@ -80,6 +92,18 @@ abstract public class ElfRelocationHandler implements ExtensionPoint { ") Symbol = " + symbolName + " (0x" + Long.toHexString(symbolIndex) + ")."); } + /** + * Generate error log entry and bookmark at relocationAddress indicating + * an unsupported RELR relocation. + * @param program + * @param relocationAddress relocation address to be bookmarked + */ + public static void markAsUnsupportedRelr(Program program, Address relocationAddress) { + BookmarkManager bookmarkManager = program.getBookmarkManager(); + bookmarkManager.setBookmark(relocationAddress, BookmarkType.ERROR, + "Unsupported RELR Relocation", "ELF Extension does not specify type"); + } + /** * Generate error log entry and bookmark at relocationAddress where * import failed to transition block to initialized while processing relocation. 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 fe835b4dc1..6198ce639d 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 @@ -726,6 +726,16 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { ElfSymbol[] symbols = relocationTable.getAssociatedSymbolTable().getSymbols(); ElfRelocation[] relocs = relocationTable.getRelocations(); + boolean relrTypeUnknown = false; + long relrRelocationType = 0; + if (relocationTable.isRelrTable() && context != null) { + relrRelocationType = context.getRelrRelocationType(); + if (relrRelocationType == 0) { + relrTypeUnknown = true; + log("Failed to process RELR relocations - extension does not define RELR type"); + } + } + for (ElfRelocation reloc : relocs) { monitor.checkCanceled(); @@ -746,6 +756,12 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { byte[] bytes = elf.is64Bit() ? new byte[8] : new byte[4]; + long type = reloc.getType(); + if (relrRelocationType != 0) { + type = relrRelocationType; + reloc.setType(relrRelocationType); + } + try { MemoryBlock relocBlock = memory.getBlock(relocAddr); if (relocBlock == null) { @@ -758,7 +774,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { catch (Exception e) { Msg.error(this, "Unexpected Exception", e); ElfRelocationHandler.markAsUninitializedMemory(program, relocAddr, - reloc.getType(), reloc.getSymbolIndex(), symbolName, log); + type, reloc.getSymbolIndex(), symbolName, log); continue; } } @@ -766,11 +782,15 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { memory.getBytes(relocAddr, bytes); if (context != null && context.hasRelocationHandler()) { - context.processRelocation(reloc, relocAddr); + if (relrTypeUnknown) { + ElfRelocationHandler.markAsUnsupportedRelr(program, relocAddr); + } + else { + context.processRelocation(reloc, relocAddr); + } } } catch (MemoryAccessException e) { - long type = reloc.getType(); if (type != 0) { // ignore if type 0 which is always NONE (no relocation performed) log("Unable to perform relocation: Type = " + type + " (0x" + Long.toHexString(type) + ") at " + relocAddr + " (Symbol = " + symbolName + @@ -956,7 +976,14 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { private void markupRelocationTable(Address relocTableAddr, ElfRelocationTable relocTable, TaskMonitor monitor) { try { - listing.createData(relocTableAddr, relocTable.toDataType()); + DataType dataType = relocTable.toDataType(); + if (dataType != null) { + listing.createData(relocTableAddr, dataType); + } + else { + listing.setComment(relocTableAddr, CodeUnit.PRE_COMMENT, + "ELF Relocation Table (markup not yet supported)"); + } } catch (Exception e) { log("Failed to properly markup relocation table: " + getMessage(e)); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FactoryStructureDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FactoryStructureDataType.java index 1a6f518dfc..96675b512e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FactoryStructureDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FactoryStructureDataType.java @@ -34,11 +34,13 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor super(null, name, dtm); } + @Override public abstract DataType clone(DataTypeManager dtm); /** * @see ghidra.program.model.data.DataType#getLength() */ + @Override public int getLength() { return -1; } @@ -46,6 +48,7 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor /** * @see ghidra.program.model.data.DataType#getValue(ghidra.program.model.mem.MemBuffer, ghidra.docking.settings.Settings, int) */ + @Override public Object getValue(MemBuffer buf, Settings settings, int length) { return null; } @@ -53,6 +56,7 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor /** * @see ghidra.program.model.data.DataType#getRepresentation(ghidra.program.model.mem.MemBuffer, ghidra.docking.settings.Settings, int) */ + @Override public String getRepresentation(MemBuffer buf, Settings settings, int length) { return null; } @@ -60,10 +64,12 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor /** * @see ghidra.program.model.data.DataType#getDescription() */ + @Override public String getDescription() { return "Dynamic Data Type should not be instantiated directly"; } + @Override public DataType getDataType(MemBuffer buf) { Structure struct = new StructureDataType(getName(), 0); if (buf != null) { @@ -80,7 +86,7 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor * @param buf * @return Returns a new structure with the correct category. */ - private Structure setCategoryPath(Structure struct, MemBuffer buf) { + protected Structure setCategoryPath(Structure struct, MemBuffer buf) { CategoryPath path = CategoryPath.ROOT; try { path = @@ -94,8 +100,9 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor } private void setCategory(DataType dt, CategoryPath path) { - if (dt == null) + if (dt == null) { return; + } try { dt.setCategoryPath(path); @@ -105,15 +112,15 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor if (dt instanceof Structure) { Structure struct = (Structure) dt; DataTypeComponent[] comps = struct.getDefinedComponents(); - for (int i = 0; i < comps.length; i++) { - setCategory(comps[i].getDataType(), path); + for (DataTypeComponent comp : comps) { + setCategory(comp.getDataType(), path); } } else if (dt instanceof Union) { Union union = (Union) dt; DataTypeComponent[] comps = union.getComponents(); - for (int i = 0; i < comps.length; i++) { - setCategory(comps[i].getDataType(), path); + for (DataTypeComponent comp : comps) { + setCategory(comp.getDataType(), path); } } else if (dt instanceof TypeDef) { 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 f82bc98e51..729606616d 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 @@ -29,6 +29,11 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler { return elf.e_machine() == ElfConstants.EM_AARCH64; } + @Override + public int getRelrRelocationType() { + return AARCH64_ElfRelocationConstants.R_AARCH64_RELATIVE; + } + @Override public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, Address relocationAddress) throws MemoryAccessException, NotFoundException { 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 ee19ded489..147b410d9a 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 @@ -29,6 +29,11 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler { return elf.e_machine() == ElfConstants.EM_386; } + @Override + public int getRelrRelocationType() { + return X86_32_ElfRelocationConstants.R_386_RELATIVE; + } + @Override public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, Address relocationAddress) throws MemoryAccessException, NotFoundException { 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 74309ae747..213a957b31 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 @@ -29,6 +29,11 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler { return elf.e_machine() == ElfConstants.EM_X86_64; } + @Override + public int getRelrRelocationType() { + return X86_64_ElfRelocationConstants.R_X86_64_RELATIVE; + } + @Override public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, Address relocationAddress) throws MemoryAccessException, NotFoundException {