All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.fornwall.jelf.ElfDynamicStructure Maven / Gradle / Ivy

There is a newer version: 0.9.8
Show newest version
package net.fornwall.jelf;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#dynamic_section
 * 
 * "If an object file participates in dynamic linking, its program header table will have an element of type PT_DYNAMIC. This ``segment'' contains the .dynamic
 * section. A special symbol, _DYNAMIC, labels the section, which contains an array of the following structures."
 * 
 * 
 * typedef struct { Elf32_Sword d_tag; union { Elf32_Word d_val; Elf32_Addr d_ptr; } d_un; } Elf32_Dyn;
 * extern Elf32_Dyn _DYNAMIC[];
 * 
 * typedef struct { Elf64_Sxword d_tag; union { Elf64_Xword d_val; Elf64_Addr d_ptr; } d_un; } Elf64_Dyn;
 * extern Elf64_Dyn _DYNAMIC[];
 * 
* *
 * http://www.sco.com/developers/gabi/latest/ch5.dynamic.html:
 * 
 * Name	        		Value		d_un		Executable	Shared Object
 * ----------------------------------------------------------------------
 * DT_NULL	    		0			ignored		mandatory	mandatory
 * DT_NEEDED			1			d_val		optional	optional
 * DT_PLTRELSZ			2			d_val		optional	optional
 * DT_PLTGOT			3			d_ptr		optional	optional
 * DT_HASH				4			d_ptr		mandatory	mandatory
 * DT_STRTAB			5			d_ptr		mandatory	mandatory
 * DT_SYMTAB			6			d_ptr		mandatory	mandatory
 * DT_RELA				7			d_ptr		mandatory	optional
 * DT_RELASZ			8			d_val		mandatory	optional
 * DT_RELAENT			9			d_val		mandatory	optional
 * DT_STRSZ				10			d_val		mandatory	mandatory
 * DT_SYMENT			11			d_val		mandatory	mandatory
 * DT_INIT  			12			d_ptr		optional	optional
 * DT_FINI	    		13			d_ptr		optional	optional
 * DT_SONAME			14			d_val		ignored		optional
 * DT_RPATH*			15			d_val		optional	ignored
 * DT_SYMBOLIC*			16			ignored		ignored		optional
 * DT_REL	    		17			d_ptr		mandatory	optional
 * DT_RELSZ	    		18			d_val		mandatory	optional
 * DT_RELENT			19			d_val		mandatory	optional
 * DT_PLTREL			20			d_val		optional	optional
 * DT_DEBUG	    		21			d_ptr		optional	ignored
 * DT_TEXTREL*			22			ignored		optional	optional
 * DT_JMPREL			23			d_ptr		optional	optional
 * DT_BIND_NOW*			24			ignored		optional	optional
 * DT_INIT_ARRAY		25			d_ptr		optional	optional
 * DT_FINI_ARRAY		26			d_ptr		optional	optional
 * DT_INIT_ARRAYSZ		27			d_val		optional	optional
 * DT_FINI_ARRAYSZ		28			d_val		optional	optional
 * DT_RUNPATH			29			d_val		optional	optional
 * DT_FLAGS				30			d_val		optional	optional
 * DT_ENCODING			32			unspecified	unspecified	unspecified
 * DT_PREINIT_ARRAY		32			d_ptr		optional	ignored
 * DT_PREINIT_ARRAYSZ	33			d_val		optional	ignored
 * DT_LOOS				0x6000000D	unspecified	unspecified	unspecified
 * DT_HIOS				0x6ffff000	unspecified	unspecified	unspecified
 * DT_LOPROC			0x70000000	unspecified	unspecified	unspecified
 * DT_HIPROC			0x7fffffff	unspecified	unspecified	unspecified
 * 
*/ public class ElfDynamicStructure { private static final Log log = LogFactory.getLog(ElfDynamicStructure.class); private static final int DT_NULL = 0; private static final int DT_NEEDED = 1; private static final int DT_PLTRELSZ = 2; public static final int DT_PLTGOT = 3; private static final int DT_HASH = 4; /** DT_STRTAB entry holds the address, not offset, of the dynamic string table. */ private static final int DT_STRTAB = 5; private static final int DT_SYMTAB = 6; public static final int DT_RELA = 7; public static final int DT_RELASZ = 8; public static final int DT_RELAENT = 9; /** The size in bytes of the {@link #DT_STRTAB} string table. */ private static final int DT_STRSZ = 10; private static final int DT_SYMENT = 11; private static final int DT_INIT = 12; public static final int DT_FINI = 13; private static final int DT_SONAME = 14; public static final int DT_RPATH = 15; private static final int DT_REL = 17; private static final int DT_RELSZ = 18; private static final int DT_RELENT = 19; private static final int DT_JMPREL = 23; private static final int DT_INIT_ARRAY = 25; private static final int DT_INIT_ARRAYSZ = 27; public static final int DT_RUNPATH = 29; private static final int DT_PREINIT_ARRAY = 32; private static final int DT_PREINIT_ARRAYSZ = 33; private static final int DT_VERSYM = 0x6ffffff0; private static final int DT_GNU_HASH = 0x6ffffef5; private static final int DT_RELACOUNT = 0x6ffffff9; private static final int DT_RELCOUNT = 0x6ffffffa; private static final int DT_FLAGS_1 = 0x6ffffffb; private static final int DT_VERDEF = 0x6ffffffc; /* Address of version definition */ private static final int DT_VERDEFNUM = 0x6ffffffd; /* Number of version definitions */ private static final int DT_VERNEEDED = 0x6ffffffe; private static final int DT_VERNEEDNUM = 0x6fffffff; private static final int DT_ANDROID_REL = 0x6000000f; private static final int DT_ANDROID_RELSZ = 0x60000010; private static final int DT_ANDROID_RELA = 0x60000011; private static final int DT_ANDROID_RELASZ = 0x60000012; /** Some values of {@link #DT_FLAGS_1}. */ public static final int DF_1_NOW = 0x00000001; /* Set RTLD_NOW for this object. */ public static final int DF_1_GLOBAL = 0x00000002; /* Set RTLD_GLOBAL for this object. */ public static final int DF_1_GROUP = 0x00000004; /* Set RTLD_GROUP for this object. */ public static final int DF_1_NODELETE = 0x00000008; /* Set RTLD_NODELETE for this object. */ /** For the {@link #DT_STRTAB}. Mandatory. */ private long dt_strtab_offset; /** For the {@link #DT_STRSZ}. Mandatory. */ private int dt_strtab_size; private MemoizedObject dtStringTable; private final int[] dtNeeded; private final int soName; private final int init; private long initArrayOffset, preInitArrayOffset; private int initArraySize, preInitArraySize; private MemoizedObject initArray, preInitArray; private MemoizedObject symbolStructure; private int symbolEntrySize; private long symbolOffset; private long hashOffset, gnuHashOffset; private long relOffset; private int relSize, relEntrySize; private long pltRelOffset; private int pltRelSize; private long androidRelOffset, androidRelAOffset; private int androidRelSize, androidRelASize; private MemoizedObject[] rel, pltRel; private MemoizedObject androidRelocation; ElfDynamicStructure(final ElfParser parser, long offset, int size) throws IOException { parser.seek(offset); int numEntries = size / (parser.elfFile.objectSize == ElfFile.CLASS_32 ? 8 : 16); List dtNeededList = new ArrayList<>(); // Except for the DT_NULL element at the end of the array, and the relative order of DT_NEEDED elements, entries // may appear in any order. So important to use lazy evaluation to only evaluating e.g. DT_STRTAB after the // necessary DT_STRSZ is read. int soName = -1; int init = 0; loop: for (int i = 0; i < numEntries; i++) { long d_tag = parser.readIntOrLong(); final long d_val_or_ptr = parser.readIntOrLong(); switch ((int) d_tag) { case DT_NULL: // A DT_NULL element ends the array (may be following DT_NULL values, but no need to look at them). break loop; case DT_NEEDED: dtNeededList.add((int) d_val_or_ptr); break; case DT_STRTAB: dt_strtab_offset = d_val_or_ptr; break; case DT_STRSZ: if (d_val_or_ptr > Integer.MAX_VALUE) throw new ElfException("Too large DT_STRSZ: " + d_val_or_ptr); dt_strtab_size = (int) d_val_or_ptr; break; case DT_SONAME: soName = (int) d_val_or_ptr; break; case DT_INIT: init = (int) d_val_or_ptr; break; case DT_INIT_ARRAY: initArrayOffset = d_val_or_ptr; break; case DT_INIT_ARRAYSZ: initArraySize = (int) d_val_or_ptr; break; case DT_PREINIT_ARRAY: preInitArrayOffset = d_val_or_ptr; break; case DT_PREINIT_ARRAYSZ: preInitArraySize = (int) d_val_or_ptr; break; case DT_SYMENT: symbolEntrySize = (int) d_val_or_ptr; break; case DT_SYMTAB: symbolOffset = d_val_or_ptr; break; case DT_HASH: hashOffset = d_val_or_ptr; break; case DT_GNU_HASH: gnuHashOffset = d_val_or_ptr; break; case DT_RELA: case DT_REL: relOffset = d_val_or_ptr; break; case DT_RELASZ: case DT_RELSZ: relSize = (int) d_val_or_ptr; break; case DT_RELAENT: case DT_RELENT: relEntrySize = (int) d_val_or_ptr; break; case DT_PLTRELSZ: pltRelSize = (int) d_val_or_ptr; break; case DT_JMPREL: pltRelOffset = d_val_or_ptr; break; case DT_ANDROID_RELASZ: androidRelASize = (int) d_val_or_ptr; break; case DT_ANDROID_RELSZ: androidRelSize = (int) d_val_or_ptr; break; case DT_ANDROID_RELA: androidRelAOffset = d_val_or_ptr; break; case DT_ANDROID_REL: androidRelOffset = d_val_or_ptr; break; case DT_VERSYM: case DT_RELACOUNT: case DT_RELCOUNT: case DT_FLAGS_1: case DT_VERDEF: case DT_VERDEFNUM: case DT_VERNEEDED: case DT_VERNEEDNUM: break; default: boolean androidTag = (d_tag & 0x60000000) != 0; if (androidTag) { log.warn("Unsupported android tag: 0x" + Long.toHexString(d_tag)); } break; } } if (dt_strtab_size > 0) { dtStringTable = new MemoizedObject() { @Override protected ElfStringTable computeValue() throws ElfException, IOException { return new ElfStringTable(parser, parser.virtualMemoryAddrToFileOffset(dt_strtab_offset), dt_strtab_size); } }; } final MemoizedObject hashTable; if (hashOffset > 0) { hashTable = new MemoizedObject() { @Override protected HashTable computeValue() throws ElfException, IOException { return new ElfHashTable(parser, parser.virtualMemoryAddrToFileOffset(hashOffset), -1); } }; } else if(gnuHashOffset > 0) { hashTable = new MemoizedObject() { @Override protected HashTable computeValue() throws ElfException, IOException { return new ElfGnuHashTable(parser, parser.virtualMemoryAddrToFileOffset(gnuHashOffset)); } }; } else { hashTable = null; } if (symbolOffset > 0) { symbolStructure = new MemoizedObject() { @Override protected ElfSymbolStructure computeValue() throws ElfException, IOException { return new ElfSymbolStructure(parser, parser.virtualMemoryAddrToFileOffset(symbolOffset), symbolEntrySize, dtStringTable, hashTable); } }; } if (relOffset > 0) { int num_entries = relSize / relEntrySize; rel = MemoizedObject.uncheckedArray(num_entries); final long fileOffset = parser.virtualMemoryAddrToFileOffset(relOffset); for (int i = 0; i < num_entries; i++) { final long relocationOffset = fileOffset + (i * relEntrySize); rel[i] = new MemoizedObject() { @Override public ElfRelocation computeValue() throws IOException { return new ElfRelocation(parser, relocationOffset, relEntrySize, symbolStructure.getValue()); } }; } } if (pltRelOffset > 0) { int num_entries = pltRelSize / relEntrySize; pltRel = MemoizedObject.uncheckedArray(num_entries); final long fileOffset = parser.virtualMemoryAddrToFileOffset(pltRelOffset); for (int i = 0; i < num_entries; i++) { final long relocationOffset = fileOffset + (i * relEntrySize); pltRel[i] = new MemoizedObject() { @Override public ElfRelocation computeValue() throws IOException { return new ElfRelocation(parser, relocationOffset, relEntrySize, symbolStructure.getValue()); } }; } } if (androidRelOffset > 0) { assert symbolStructure != null; androidRelocation = new MemoizedObject() { @Override protected AndroidRelocation computeValue() throws ElfException, IOException { parser.seek(parser.virtualMemoryAddrToFileOffset(androidRelOffset)); byte[] magic = new byte[4]; parser.read(magic); if (androidRelSize >= 4 && "APS2".equals(new String(magic))) { ByteBuffer androidRelData = parser.readBuffer(androidRelSize - 4); return new AndroidRelocation(parser, symbolStructure.getValue(), androidRelData, false); } else { throw new IllegalStateException("bad android relocation header."); } } }; } else if (androidRelAOffset > 0) { assert symbolStructure != null; androidRelocation = new MemoizedObject() { @Override protected AndroidRelocation computeValue() throws ElfException, IOException { parser.seek(parser.virtualMemoryAddrToFileOffset(androidRelAOffset)); byte[] magic = new byte[4]; parser.read(magic); if (androidRelASize >= 4 && "APS2".equals(new String(magic))) { ByteBuffer androidRelData = parser.readBuffer(androidRelASize - 4); return new AndroidRelocation(parser, symbolStructure.getValue(), androidRelData, true); } else { throw new IllegalStateException("bad android relocation header."); } } }; } if (initArraySize > 0) { initArray = new MemoizedObject() { @Override protected ElfInitArray computeValue() throws ElfException, IOException { return new ElfInitArray(parser, parser.virtualMemoryAddrToFileOffset(initArrayOffset), initArraySize); } }; } if (preInitArraySize > 0) { preInitArray = new MemoizedObject() { @Override protected ElfInitArray computeValue() throws ElfException, IOException { return new ElfInitArray(parser, parser.virtualMemoryAddrToFileOffset(preInitArrayOffset), preInitArraySize); } }; } dtNeeded = new int[dtNeededList.size()]; for (int i = 0, len = dtNeeded.length; i < len; i++) { dtNeeded[i] = dtNeededList.get(i); } this.soName = soName; this.init = init; } public String getSOName(String fileName) throws IOException { ElfStringTable stringTable = dtStringTable.getValue(); return soName == -1 ? fileName : stringTable.get(soName); } public int getInit() { return init; } public List getNeededLibraries() throws ElfException, IOException { List result = new ArrayList<>(); ElfStringTable stringTable = dtStringTable.getValue(); for (int needed : dtNeeded) { result.add(stringTable.get(needed)); } return result; } public long getInitArrayOffset() { return initArrayOffset; } public long getPreInitArrayOffset() { return preInitArrayOffset; } public int getInitArraySize() { return initArraySize; } public int getPreInitArraySize() { return preInitArraySize; } public ElfInitArray getInitArray() throws IOException { return initArray == null ? null : initArray.getValue(); } public ElfInitArray getPreInitArray() throws IOException { return preInitArray == null ? null : preInitArray.getValue(); } public ElfSymbolStructure getSymbolStructure() throws IOException { return symbolStructure.getValue(); } public Collection> getRelocations() throws IOException { List> list = new ArrayList<>(); if (androidRelocation != null) { for (MemoizedObject elfRelocationMemoizedObject : androidRelocation.getValue()) { list.add(elfRelocationMemoizedObject); } } if (rel != null) { Collections.addAll(list, rel); } if (pltRel != null) { Collections.addAll(list, pltRel); } return list; } @Override public String toString() { return "ElfDynamicStructure[]"; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy