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