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/plugin/exceptionhandlers/gcc/structures/ehFrame/FrameDescriptionEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/exceptionhandlers/gcc/structures/ehFrame/FrameDescriptionEntry.java
index 30ef373b2f..02815145da 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/exceptionhandlers/gcc/structures/ehFrame/FrameDescriptionEntry.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/exceptionhandlers/gcc/structures/ehFrame/FrameDescriptionEntry.java
@@ -269,14 +269,6 @@ public class FrameDescriptionEntry extends GccAnalysisClass {
createAndCommentData(program, addr, encodedDt, comment, CodeUnit.EOL_COMMENT);
if (pcBeginAddr.getOffset() != 0x0) {
- // if the program was moved from a preferred image base, need to adjust
- // the beginning of frame pointer
- Long oib = ElfLoader.getElfOriginalImageBase(program);
- if (oib != null) {
- long imageBaseOffset = program.getImageBase().getOffset() - oib;
- pcBeginAddr = pcBeginAddr.add(imageBaseOffset);
- }
-
program.getReferenceManager().addMemoryReference(addr, pcBeginAddr, RefType.DATA,
SourceType.ANALYSIS, 0);
}
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 849d391b70..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;
@@ -94,6 +95,15 @@ public class ElfDynamicType {
public static ElfDynamicType DT_FLAGS = addDefaultDynamicType(30, "DT_FLAGS",
"Flags for the object being loaded", ElfDynamicValueType.VALUE);
+ // Experimental RELR relocation support
+ // - see proposal at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ 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_RELRENT",
+ "Size of Relr relocation entry", ElfDynamicValueType.VALUE);
+
public static final int DF_ORIGIN = 0x1; // $ORIGIN processing required
public static final int DF_SYMBOLIC = 0x2; // Symbolic symbol resolution required
public static final int DF_TEXTREL = 0x4; // Text relocations exist
@@ -114,12 +124,18 @@ public class ElfDynamicType {
"DT_ANDROID_REL", "Address of Rel relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELSZ = addDefaultDynamicType(0x60000010,
"DT_ANDROID_RELSZ", "Total size of Rel relocs", ElfDynamicValueType.VALUE);
-
public static ElfDynamicType DT_ANDROID_RELA = addDefaultDynamicType(0x60000011,
"DT_ANDROID_RELA", "Address of Rela relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELASZ = addDefaultDynamicType(0x60000012,
"DT_ANDROID_RELASZ", "Total size of Rela relocs", ElfDynamicValueType.VALUE);
+ 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_RELRSZ", "Total size of Relr relocs", ElfDynamicValueType.VALUE);
+ public static ElfDynamicType DT_ANDROID_RELRENT = addDefaultDynamicType(0x6FFFE003,
+ "DT_ANDROID_RELRENT", "Size of Relr relocation entry", ElfDynamicValueType.VALUE);
+
// Value Range (??): 0x6ffffd00 - 0x6ffffdff
public static ElfDynamicType DT_GNU_PRELINKED = addDefaultDynamicType(0x6ffffdf5,
@@ -218,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 9d1e2dc423..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,6 +372,12 @@ public class ElfHeader implements StructConverter, Writeable {
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELA, null,
ElfDynamicType.DT_ANDROID_RELASZ, true);
+ 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);
// In general the above dynamic relocation tables should cover most cases, we will
@@ -390,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()) {
@@ -440,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(),
@@ -527,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 0a403ce15d..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;
@@ -38,30 +40,35 @@ import ghidra.util.exception.AssertException;
*
* REL entry:
*
- * typedef struct {
- * Elf32_Addr r_offset;
- * Elf32_Word r_info;
- * } Elf32_Rel;
+ * typedef struct {
+ * Elf32_Addr r_offset;
+ * Elf32_Word r_info;
+ * } Elf32_Rel;
*
- * typedef struct {
- * Elf64_Addr r_offset;
- * Elf64_Xword r_info;
- * } Elf64_Rel;
+ * typedef struct {
+ * Elf64_Addr r_offset;
+ * Elf64_Xword r_info;
+ * } Elf64_Rel;
*
* RELA entry with addend:
*
- * * typedef struct {
- * Elf32_Addr r_offset;
- * Elf32_Word r_info;
- * Elf32_Sword r_addend;
- * } Elf32_Rela;
+ * typedef struct {
+ * Elf32_Addr r_offset;
+ * Elf32_Word r_info;
+ * Elf32_Sword r_addend;
+ * } Elf32_Rela;
+ *
+ * typedef struct {
+ * Elf64_Addr r_offset; //Address
+ * Elf64_Xword r_info; //Relocation type and symbol index
+ * Elf64_Sxword r_addend; //Addend
+ * } Elf64_Rela;
+ *
+ * RELR entry (see SHT_RELR, DT_RELR):
+ * 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 struct {
- * Elf64_Addr r_offset; //Address
- * Elf64_Xword r_info; //Relocation type and symbol index
- * Elf64_Sxword r_addend; //Addend
- * } Elf64_Rela;
- *
*
*/
public class ElfRelocation implements ByteArrayConverter, StructConverter {
@@ -261,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() {
@@ -269,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
@@ -364,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/ElfSectionHeaderConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSectionHeaderConstants.java
index dc9507b934..7745852af8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSectionHeaderConstants.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSectionHeaderConstants.java
@@ -108,6 +108,8 @@ public class ElfSectionHeaderConstants {
public static final int SHT_GROUP = 17;
/**Extended section indeces*/
public static final int SHT_SYMTAB_SHNDX = 18;
+ /**Experimental support - see proposal at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg */
+ public static final int SHT_RELR = 19;
// OS Specific Section Types
@@ -116,6 +118,9 @@ public class ElfSectionHeaderConstants {
/**Android relocation entries with explicit addends*/
public static final int SHT_ANDROID_RELA = 0x60000002;
+ /**Android's experimental support for SHT_RELR sections (see above) */
+ public static final int SHT_ANDROID_RELR = 0x6fffff00;
+
/**Object attributes */
public static final int SHT_GNU_ATTRIBUTES = 0x6ffffff5;
/**GNU-style hash table */
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 {