1 // Copyright Yazan Dabain 2014. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module elf; 7 8 public import elf.sections; 9 10 import elf.low, elf.low32, elf.low64, elf.meta; 11 12 import std.mmfile; 13 import std.exception; 14 import std.conv : to; 15 import std.typecons : Nullable; 16 17 alias enforce = enforce!ELFException; 18 19 abstract class ELF { 20 MmFile m_file; 21 22 private this(MmFile file) { 23 this.m_file = file; 24 } 25 26 static ELF fromFile(string filepath) { 27 MmFile file = new MmFile(filepath); 28 return ELF.fromFile(file); 29 } 30 31 static ELF fromFile(MmFile file) { 32 enforce(file.length > 16); 33 enforce(file[0 .. 4] == ['\x7f', 'E', 'L', 'F']); 34 bool is32Bit = (file[4] == 1); 35 bool is64Bit = (file[4] == 2); 36 37 if (is32Bit) { 38 return new ELF32(file); 39 } else if (is64Bit) { 40 return new ELF64(file); 41 } else { 42 throw new ELFException("invalid elf file class"); 43 } 44 } 45 46 @property ELFHeader header(); 47 ELFSection buildSection(ubyte[] section); 48 49 @property auto sections() { 50 struct Sections { 51 private size_t m_currentIndex = 0; 52 ELF m_elf; 53 54 this(ELF elf) { this.m_elf = elf; } 55 56 @property bool empty() { return m_currentIndex >= m_elf.header.numberOfSectionHeaderEntries; } 57 @property size_t length() { return m_elf.header.numberOfSectionHeaderEntries - m_currentIndex; } 58 59 @property ELFSection front() { 60 enforce(!empty, "out of bounds exception"); 61 return this[m_currentIndex]; 62 } 63 64 void popFront() { 65 enforce(!empty, "out of bounds exception"); 66 this.m_currentIndex++; 67 } 68 69 @property typeof(this) save() { 70 return this; 71 } 72 73 ELFSection opIndex(size_t index) { 74 enforce(index < m_elf.header.numberOfSectionHeaderEntries, "out of bounds exception"); 75 auto sectionStart = m_elf.header.sectionHeaderOffset + index * m_elf.header.sizeOfSectionHeaderEntry; 76 auto section = m_elf.m_file[sectionStart .. sectionStart + m_elf.header.sizeOfSectionHeaderEntry]; 77 return this.m_elf.buildSection(cast(ubyte[]) section); 78 } 79 } 80 return Sections(this); 81 } 82 83 // linear lookup 84 Nullable!ELFSection getSection(string name) { 85 foreach (section; this.sections) { 86 if (section.name == name) return Nullable!ELFSection(section); 87 } 88 return Nullable!ELFSection(); 89 } 90 91 StringTable getSectionNamesStringTable() { 92 ELFSection section = this.sections[this.header.sectionHeaderStringTableIndex]; 93 return StringTable(section); 94 } 95 96 Nullable!StringTable getSymbolsStringTable() { 97 Nullable!ELFSection section = this.getSection(".strtab"); 98 if (section.isNull) return Nullable!StringTable(); 99 else return Nullable!StringTable(StringTable(section.get())); 100 } 101 } 102 103 final class ELF64 : ELF { 104 ELFHeader64 m_header; 105 106 this(MmFile file) { 107 super(file); 108 109 ELFHeader64L headerData = *(cast(ELFHeader64L*) file[0 .. ELFHeader64L.sizeof].ptr); 110 this.m_header = new ELFHeader64(headerData); 111 } 112 113 override @property ELFHeader header() { 114 return this.m_header; 115 } 116 117 override ELFSection64 buildSection(ubyte[] sectionData) { 118 enforce(sectionData.length == ELFSection64L.sizeof); 119 ELFSection64L sectionRep = *(cast(ELFSection64L*) sectionData.ptr); 120 ELFSection64 section = new ELFSection64(this, sectionRep); 121 section.m_elf = this; 122 return section; 123 } 124 } 125 126 final class ELF32 : ELF { 127 ELFHeader32 m_header; 128 129 this(MmFile file) { 130 super(file); 131 132 ELFHeader32L headerData = *(cast(ELFHeader32L*) file[0 .. ELFHeader32L.sizeof].ptr); 133 this.m_header = new ELFHeader32(headerData); 134 } 135 136 override @property ELFHeader header() { 137 return this.m_header; 138 } 139 140 override ELFSection32 buildSection(ubyte[] sectionData) { 141 enforce(sectionData.length == ELFSection32L.sizeof); 142 ELFSection32L sectionRep = *(cast(ELFSection32L*) sectionData.ptr); 143 ELFSection32 section = new ELFSection32(this, sectionRep); 144 return section; 145 } 146 } 147 148 abstract class ELFHeader { 149 @property: 150 @ReadFrom("ident") Identifier identifier(); 151 @ReadFrom("type") ObjectFileType objectFileType(); 152 @ReadFrom("machine") TargetISA machineISA(); 153 @ReadFrom("version_") ELF_Word version_(); 154 @ReadFrom("entry") ELF_Addr entryPoint(); 155 @ReadFrom("phoff") ELF_Off programHeaderOffset(); 156 @ReadFrom("shoff") ELF_Off sectionHeaderOffset(); 157 @ReadFrom("phentsize") ELF_Half sizeOfProgramHeaderEntry(); 158 @ReadFrom("phnum") ELF_Half numberOfProgramHeaderEntries(); 159 @ReadFrom("shentsize") ELF_Half sizeOfSectionHeaderEntry(); 160 @ReadFrom("shnum") ELF_Half numberOfSectionHeaderEntries(); 161 @ReadFrom("shstrndx") ELF_Half sectionHeaderStringTableIndex(); 162 } 163 164 final class ELFHeader32 : ELFHeader { 165 private ELFHeader32L m_data; 166 mixin(generateVirtualReads!(ELFHeader, "m_data")); 167 168 this(ELFHeader32L data) { 169 this.m_data = data; 170 } 171 } 172 173 final class ELFHeader64 : ELFHeader { 174 private ELFHeader64L m_data; 175 mixin(generateVirtualReads!(ELFHeader, "m_data")); 176 177 this(ELFHeader64L data) { 178 this.m_data = data; 179 } 180 } 181 182 abstract class ELFSection { 183 package ELF m_elf; 184 185 @property: 186 @ReadFrom("name") ELF_Word nameIndex(); 187 @ReadFrom("type") SectionType type(); 188 @ReadFrom("flags") SectionFlag flags(); 189 @ReadFrom("address") ELF_Addr address(); 190 @ReadFrom("offset") ELF_Off offset(); 191 @ReadFrom("size") ELF_XWord size(); 192 @ReadFrom("link") ELF_Word link(); 193 @ReadFrom("info") ELF_Word info(); 194 @ReadFrom("addralign") ELF_XWord addrAlign(); 195 @ReadFrom("entsize") ELF_XWord entrySize(); 196 197 ubyte bits(); 198 199 auto name() { 200 return m_elf.getSectionNamesStringTable().getStringAt(this.nameIndex()); 201 } 202 203 auto contents() { 204 return cast(ubyte[]) m_elf.m_file[offset() .. offset() + size()]; 205 } 206 } 207 208 final class ELFSection32 : ELFSection { 209 private ELFSection32L m_data; 210 mixin(generateVirtualReads!(ELFSection, "m_data")); 211 212 this(ELF32 elf, ELFSection32L data) { 213 this.m_elf = elf; 214 this.m_data = data; 215 } 216 217 override @property ubyte bits() { 218 return 32; 219 } 220 } 221 222 final class ELFSection64 : ELFSection { 223 private ELFSection64L m_data; 224 mixin(generateVirtualReads!(ELFSection, "m_data")); 225 226 this(ELF64 elf, ELFSection64L data) { 227 this.m_elf = elf; 228 this.m_data = data; 229 } 230 231 override @property ubyte bits() { 232 return 64; 233 } 234 } 235 236 class ELFException : Exception { 237 this(string msg, string file = __FILE__, size_t line = __LINE__) { 238 super(msg, file, line); 239 } 240 }