Merge remote-tracking branch 'origin/GP-348_ghidra1_ElfRelrRelocations' into Ghidra_9.2

This commit is contained in:
ghidra1 2020-11-03 14:11:25 -05:00
commit 149407a682
15 changed files with 371 additions and 46 deletions

View file

@ -414,7 +414,14 @@ public class ElfBinaryAnalysisCommand extends FlatProgramAPI
// elf.getSection(relocationTable.getFileOffset()); // may be null // elf.getSection(relocationTable.getFileOffset()); // may be null
Address relocationTableAddress = addr(relocationTable.getFileOffset()); Address relocationTableAddress = addr(relocationTable.getFileOffset());
try { 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) { catch (Exception e) {
messages.appendMsg( messages.appendMsg(

View file

@ -269,14 +269,6 @@ public class FrameDescriptionEntry extends GccAnalysisClass {
createAndCommentData(program, addr, encodedDt, comment, CodeUnit.EOL_COMMENT); createAndCommentData(program, addr, encodedDt, comment, CodeUnit.EOL_COMMENT);
if (pcBeginAddr.getOffset() != 0x0) { 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, program.getReferenceManager().addMemoryReference(addr, pcBeginAddr, RefType.DATA,
SourceType.ANALYSIS, 0); SourceType.ANALYSIS, 0);
} }

View file

@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.elf;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import ghidra.util.Msg;
import ghidra.util.StringUtilities; import ghidra.util.StringUtilities;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@ -94,6 +95,15 @@ public class ElfDynamicType {
public static ElfDynamicType DT_FLAGS = addDefaultDynamicType(30, "DT_FLAGS", public static ElfDynamicType DT_FLAGS = addDefaultDynamicType(30, "DT_FLAGS",
"Flags for the object being loaded", ElfDynamicValueType.VALUE); "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_ORIGIN = 0x1; // $ORIGIN processing required
public static final int DF_SYMBOLIC = 0x2; // Symbolic symbol resolution required public static final int DF_SYMBOLIC = 0x2; // Symbolic symbol resolution required
public static final int DF_TEXTREL = 0x4; // Text relocations exist 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); "DT_ANDROID_REL", "Address of Rel relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELSZ = addDefaultDynamicType(0x60000010, public static ElfDynamicType DT_ANDROID_RELSZ = addDefaultDynamicType(0x60000010,
"DT_ANDROID_RELSZ", "Total size of Rel relocs", ElfDynamicValueType.VALUE); "DT_ANDROID_RELSZ", "Total size of Rel relocs", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_ANDROID_RELA = addDefaultDynamicType(0x60000011, public static ElfDynamicType DT_ANDROID_RELA = addDefaultDynamicType(0x60000011,
"DT_ANDROID_RELA", "Address of Rela relocs", ElfDynamicValueType.ADDRESS); "DT_ANDROID_RELA", "Address of Rela relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELASZ = addDefaultDynamicType(0x60000012, public static ElfDynamicType DT_ANDROID_RELASZ = addDefaultDynamicType(0x60000012,
"DT_ANDROID_RELASZ", "Total size of Rela relocs", ElfDynamicValueType.VALUE); "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 // Value Range (??): 0x6ffffd00 - 0x6ffffdff
public static ElfDynamicType DT_GNU_PRELINKED = addDefaultDynamicType(0x6ffffdf5, public static ElfDynamicType DT_GNU_PRELINKED = addDefaultDynamicType(0x6ffffdf5,
@ -218,7 +234,9 @@ public class ElfDynamicType {
return type; return type;
} }
catch (DuplicateNameException e) { 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);
} }
} }

View file

@ -372,6 +372,12 @@ public class ElfHeader implements StructConverter, Writeable {
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELA, null, parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELA, null,
ElfDynamicType.DT_ANDROID_RELASZ, true); 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); parseJMPRelocTable(relocationTableList);
// In general the above dynamic relocation tables should cover most cases, we will // 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(); int sectionHeaderType = section.getType();
if (sectionHeaderType == ElfSectionHeaderConstants.SHT_REL || if (sectionHeaderType == ElfSectionHeaderConstants.SHT_REL ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA || sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_RELR ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL || sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) { sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELR) {
for (ElfRelocationTable relocTable : relocationTableList) { for (ElfRelocationTable relocTable : relocationTableList) {
if (relocTable.getFileOffset() == section.getOffset()) { if (relocTable.getFileOffset() == section.getOffset()) {
@ -440,6 +448,10 @@ public class ElfHeader implements StructConverter, Writeable {
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) { sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) {
format = TableFormat.ANDROID; format = TableFormat.ANDROID;
} }
else if (sectionHeaderType == ElfSectionHeaderConstants.SHT_RELR ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELR) {
format = TableFormat.RELR;
}
ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader, ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader,
this, section, section.getOffset(), section.getAddress(), section.getSize(), this, section, section.getOffset(), section.getAddress(), section.getSize(),
@ -527,6 +539,10 @@ public class ElfHeader implements StructConverter, Writeable {
relocTableAddrType == ElfDynamicType.DT_ANDROID_RELA) { relocTableAddrType == ElfDynamicType.DT_ANDROID_RELA) {
format = TableFormat.ANDROID; format = TableFormat.ANDROID;
} }
else if (relocTableAddrType == ElfDynamicType.DT_RELR ||
relocTableAddrType == ElfDynamicType.DT_ANDROID_RELR) {
format = TableFormat.RELR;
}
ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader, ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader,
this, null, relocTableOffset, relocTableAddr, tableSize, tableEntrySize, this, null, relocTableOffset, relocTableAddr, tableSize, tableEntrySize,

View file

@ -22,6 +22,8 @@ import ghidra.app.util.bin.ByteArrayConverter;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter; 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.program.model.data.*;
import ghidra.util.Conv; import ghidra.util.Conv;
import ghidra.util.DataConverter; import ghidra.util.DataConverter;
@ -38,29 +40,34 @@ import ghidra.util.exception.AssertException;
* *
* REL entry: * REL entry:
* *
* typedef struct { * typedef struct {
* Elf32_Addr r_offset; * Elf32_Addr r_offset;
* Elf32_Word r_info; * Elf32_Word r_info;
* } Elf32_Rel; * } Elf32_Rel;
* *
* typedef struct { * typedef struct {
* Elf64_Addr r_offset; * Elf64_Addr r_offset;
* Elf64_Xword r_info; * Elf64_Xword r_info;
* } Elf64_Rel; * } Elf64_Rel;
* *
* RELA entry with addend: * RELA entry with addend:
* *
* * typedef struct { * typedef struct {
* Elf32_Addr r_offset; * Elf32_Addr r_offset;
* Elf32_Word r_info; * Elf32_Word r_info;
* Elf32_Sword r_addend; * Elf32_Sword r_addend;
* } Elf32_Rela; * } Elf32_Rela;
* *
* typedef struct { * typedef struct {
* Elf64_Addr r_offset; //Address * Elf64_Addr r_offset; //Address
* Elf64_Xword r_info; //Relocation type and symbol index * Elf64_Xword r_info; //Relocation type and symbol index
* Elf64_Sxword r_addend; //Addend * Elf64_Sxword r_addend; //Addend
* } Elf64_Rela; * } Elf64_Rela;
*
* RELR entry (see SHT_RELR, DT_RELR):
* NOTE: Relocation type is data <i>relative</i> and must be specified by appropriate relocation handler
* (see {@link ElfRelocationHandler#getRelrRelocationType()}) since it is not contained within the
* relocation table which only specifies <i>r_offset</i> for each entry.
* *
* </pre> * </pre>
*/ */
@ -261,6 +268,8 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter {
/** /**
* Returns the symbol index where the relocation must be made. * 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 * @return the symbol index
*/ */
public int getSymbolIndex() { public int getSymbolIndex() {
@ -269,13 +278,28 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter {
/** /**
* The type of relocation to apply. * 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 * @return type of relocation to apply
*/ */
public int getType() { public int getType() {
return (int) (is32bit ? (r_info & Conv.BYTE_MASK) : (r_info & Conv.INT_MASK)); 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 * Returns the r_info relocation entry field value
* @return r_info value * @return r_info value
@ -364,4 +388,5 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter {
} }
return is32bit ? 8 : 16; return is32bit ? 8 : 16;
} }
} }

View file

@ -34,7 +34,7 @@ import ghidra.util.Msg;
public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
public enum TableFormat { public enum TableFormat {
DEFAULT, ANDROID; DEFAULT, ANDROID, RELR;
} }
private TableFormat format; private TableFormat format;
@ -111,7 +111,10 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
reader.setPointerIndex(fileOffset); reader.setPointerIndex(fileOffset);
List<ElfRelocation> relocList; List<ElfRelocation> relocList;
if (format == TableFormat.ANDROID) { if (format == TableFormat.RELR) {
relocList = parseRelrRelocations(reader);
}
else if (format == TableFormat.ANDROID) {
relocList = parseAndroidRelocations(reader); relocList = parseAndroidRelocations(reader);
} }
else { else {
@ -139,6 +142,57 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
return relocations; return relocations;
} }
private long readNextRelrEntry(FactoryBundledWithBinaryReader reader) throws IOException {
return entrySize == 8 ? reader.readNextLong() : reader.readNextUnsignedInt();
}
private long addRelrEntry(long offset, List<ElfRelocation> relocList) {
relocList.add(ElfRelocation.createElfRelocation(factory, elfHeader, relocList.size(),
addendTypeReloc, offset, 0, 0));
return offset + entrySize;
}
private long addRelrEntries(long baseOffset, long entry, List<ElfRelocation> 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<ElfRelocation> 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<ElfRelocation> 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<ElfRelocation> parseAndroidRelocations(FactoryBundledWithBinaryReader reader) private List<ElfRelocation> parseAndroidRelocations(FactoryBundledWithBinaryReader reader)
throws IOException { throws IOException {
@ -288,6 +342,10 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
return relocTableSection; return relocTableSection;
} }
public boolean isRelrTable() {
return format == TableFormat.RELR;
}
@Override @Override
public long getFileOffset() { public long getFileOffset() {
return fileOffset; return fileOffset;
@ -300,7 +358,12 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
@Override @Override
public DataType toDataType() { 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(); return new AndroidElfRelocationTableDataType();
} }

View file

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

View file

@ -108,6 +108,8 @@ public class ElfSectionHeaderConstants {
public static final int SHT_GROUP = 17; public static final int SHT_GROUP = 17;
/**Extended section indeces*/ /**Extended section indeces*/
public static final int SHT_SYMTAB_SHNDX = 18; 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 // OS Specific Section Types
@ -116,6 +118,9 @@ public class ElfSectionHeaderConstants {
/**Android relocation entries with explicit addends*/ /**Android relocation entries with explicit addends*/
public static final int SHT_ANDROID_RELA = 0x60000002; 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 */ /**Object attributes */
public static final int SHT_GNU_ATTRIBUTES = 0x6ffffff5; public static final int SHT_GNU_ATTRIBUTES = 0x6ffffff5;
/**GNU-style hash table */ /**GNU-style hash table */

View file

@ -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, private void handleUnsupportedTLSRelocation(ElfRelocation relocation,
Address relocationAddress) { Address relocationAddress) {
long symbolIndex = relocation.getSymbolIndex(); long symbolIndex = relocation.getSymbolIndex();
@ -116,7 +125,7 @@ public class ElfRelocationContext {
* @param loadHelper Elf load helper * @param loadHelper Elf load helper
* @param relocationTable Elf relocation table * @param relocationTable Elf relocation table
* @param symbolMap Elf symbol placement map * @param symbolMap Elf symbol placement map
* @return relocation context * @return relocation context or null
*/ */
public static ElfRelocationContext getRelocationContext(ElfLoadHelper loadHelper, public static ElfRelocationContext getRelocationContext(ElfLoadHelper loadHelper,
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) { ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {

View file

@ -33,12 +33,24 @@ abstract public class ElfRelocationHandler implements ExtensionPoint {
abstract public boolean canRelocate(ElfHeader elf); 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 * 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. * is used to process relocations and manage any data required to process relocations.
* @param loadHelper Elf load helper * @param loadHelper Elf load helper
* @param relocationTable Elf relocation table * @param relocationTable Elf relocation table
* @param symbolMap Elf symbol placement map * @param symbolMap Elf symbol placement map
* @return relocation context or null if unsupported
*/ */
public ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper, public ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) { ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
@ -80,6 +92,18 @@ abstract public class ElfRelocationHandler implements ExtensionPoint {
") Symbol = " + symbolName + " (0x" + Long.toHexString(symbolIndex) + ")."); ") 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 * Generate error log entry and bookmark at relocationAddress where
* import failed to transition block to initialized while processing relocation. * import failed to transition block to initialized while processing relocation.

View file

@ -726,6 +726,16 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
ElfSymbol[] symbols = relocationTable.getAssociatedSymbolTable().getSymbols(); ElfSymbol[] symbols = relocationTable.getAssociatedSymbolTable().getSymbols();
ElfRelocation[] relocs = relocationTable.getRelocations(); 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) { for (ElfRelocation reloc : relocs) {
monitor.checkCanceled(); monitor.checkCanceled();
@ -746,6 +756,12 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
byte[] bytes = elf.is64Bit() ? new byte[8] : new byte[4]; byte[] bytes = elf.is64Bit() ? new byte[8] : new byte[4];
long type = reloc.getType();
if (relrRelocationType != 0) {
type = relrRelocationType;
reloc.setType(relrRelocationType);
}
try { try {
MemoryBlock relocBlock = memory.getBlock(relocAddr); MemoryBlock relocBlock = memory.getBlock(relocAddr);
if (relocBlock == null) { if (relocBlock == null) {
@ -758,7 +774,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
catch (Exception e) { catch (Exception e) {
Msg.error(this, "Unexpected Exception", e); Msg.error(this, "Unexpected Exception", e);
ElfRelocationHandler.markAsUninitializedMemory(program, relocAddr, ElfRelocationHandler.markAsUninitializedMemory(program, relocAddr,
reloc.getType(), reloc.getSymbolIndex(), symbolName, log); type, reloc.getSymbolIndex(), symbolName, log);
continue; continue;
} }
} }
@ -766,11 +782,15 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
memory.getBytes(relocAddr, bytes); memory.getBytes(relocAddr, bytes);
if (context != null && context.hasRelocationHandler()) { if (context != null && context.hasRelocationHandler()) {
context.processRelocation(reloc, relocAddr); if (relrTypeUnknown) {
ElfRelocationHandler.markAsUnsupportedRelr(program, relocAddr);
}
else {
context.processRelocation(reloc, relocAddr);
}
} }
} }
catch (MemoryAccessException e) { catch (MemoryAccessException e) {
long type = reloc.getType();
if (type != 0) { // ignore if type 0 which is always NONE (no relocation performed) if (type != 0) { // ignore if type 0 which is always NONE (no relocation performed)
log("Unable to perform relocation: Type = " + type + " (0x" + log("Unable to perform relocation: Type = " + type + " (0x" +
Long.toHexString(type) + ") at " + relocAddr + " (Symbol = " + symbolName + Long.toHexString(type) + ") at " + relocAddr + " (Symbol = " + symbolName +
@ -956,7 +976,14 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
private void markupRelocationTable(Address relocTableAddr, ElfRelocationTable relocTable, private void markupRelocationTable(Address relocTableAddr, ElfRelocationTable relocTable,
TaskMonitor monitor) { TaskMonitor monitor) {
try { 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) { catch (Exception e) {
log("Failed to properly markup relocation table: " + getMessage(e)); log("Failed to properly markup relocation table: " + getMessage(e));

View file

@ -34,11 +34,13 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor
super(null, name, dtm); super(null, name, dtm);
} }
@Override
public abstract DataType clone(DataTypeManager dtm); public abstract DataType clone(DataTypeManager dtm);
/** /**
* @see ghidra.program.model.data.DataType#getLength() * @see ghidra.program.model.data.DataType#getLength()
*/ */
@Override
public int getLength() { public int getLength() {
return -1; 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) * @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) { public Object getValue(MemBuffer buf, Settings settings, int length) {
return null; 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) * @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) { public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return null; return null;
} }
@ -60,10 +64,12 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor
/** /**
* @see ghidra.program.model.data.DataType#getDescription() * @see ghidra.program.model.data.DataType#getDescription()
*/ */
@Override
public String getDescription() { public String getDescription() {
return "Dynamic Data Type should not be instantiated directly"; return "Dynamic Data Type should not be instantiated directly";
} }
@Override
public DataType getDataType(MemBuffer buf) { public DataType getDataType(MemBuffer buf) {
Structure struct = new StructureDataType(getName(), 0); Structure struct = new StructureDataType(getName(), 0);
if (buf != null) { if (buf != null) {
@ -80,7 +86,7 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor
* @param buf * @param buf
* @return Returns a new structure with the correct category. * @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; CategoryPath path = CategoryPath.ROOT;
try { try {
path = path =
@ -94,8 +100,9 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor
} }
private void setCategory(DataType dt, CategoryPath path) { private void setCategory(DataType dt, CategoryPath path) {
if (dt == null) if (dt == null) {
return; return;
}
try { try {
dt.setCategoryPath(path); dt.setCategoryPath(path);
@ -105,15 +112,15 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor
if (dt instanceof Structure) { if (dt instanceof Structure) {
Structure struct = (Structure) dt; Structure struct = (Structure) dt;
DataTypeComponent[] comps = struct.getDefinedComponents(); DataTypeComponent[] comps = struct.getDefinedComponents();
for (int i = 0; i < comps.length; i++) { for (DataTypeComponent comp : comps) {
setCategory(comps[i].getDataType(), path); setCategory(comp.getDataType(), path);
} }
} }
else if (dt instanceof Union) { else if (dt instanceof Union) {
Union union = (Union) dt; Union union = (Union) dt;
DataTypeComponent[] comps = union.getComponents(); DataTypeComponent[] comps = union.getComponents();
for (int i = 0; i < comps.length; i++) { for (DataTypeComponent comp : comps) {
setCategory(comps[i].getDataType(), path); setCategory(comp.getDataType(), path);
} }
} }
else if (dt instanceof TypeDef) { else if (dt instanceof TypeDef) {

View file

@ -29,6 +29,11 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
return elf.e_machine() == ElfConstants.EM_AARCH64; return elf.e_machine() == ElfConstants.EM_AARCH64;
} }
@Override
public int getRelrRelocationType() {
return AARCH64_ElfRelocationConstants.R_AARCH64_RELATIVE;
}
@Override @Override
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
Address relocationAddress) throws MemoryAccessException, NotFoundException { Address relocationAddress) throws MemoryAccessException, NotFoundException {

View file

@ -29,6 +29,11 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
return elf.e_machine() == ElfConstants.EM_386; return elf.e_machine() == ElfConstants.EM_386;
} }
@Override
public int getRelrRelocationType() {
return X86_32_ElfRelocationConstants.R_386_RELATIVE;
}
@Override @Override
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
Address relocationAddress) throws MemoryAccessException, NotFoundException { Address relocationAddress) throws MemoryAccessException, NotFoundException {

View file

@ -29,6 +29,11 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
return elf.e_machine() == ElfConstants.EM_X86_64; return elf.e_machine() == ElfConstants.EM_X86_64;
} }
@Override
public int getRelrRelocationType() {
return X86_64_ElfRelocationConstants.R_X86_64_RELATIVE;
}
@Override @Override
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
Address relocationAddress) throws MemoryAccessException, NotFoundException { Address relocationAddress) throws MemoryAccessException, NotFoundException {