1 /** 2 * Extract symbols from a COFF object file. 3 * 4 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/scanmscoff.d, _scanmscoff.d) 8 * Documentation: https://dlang.org/phobos/dmd_scanmscoff.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/scanmscoff.d 10 */ 11 12 module dmd.scanmscoff; 13 14 version(Windows): 15 16 import core.stdc.string, core.stdc.stdlib, core.sys.windows.winnt; 17 18 import dmd.root.rmem; 19 import dmd.root.string; 20 21 import dmd.globals, dmd.errors; 22 23 private enum LOG = false; 24 25 /***************************************** 26 * Reads an object module from base[] and passes the names 27 * of any exported symbols to (*pAddSymbol)(). 28 * Params: 29 * pAddSymbol = function to pass the names to 30 * base = array of contents of object module 31 * module_name = name of the object module (used for error messages) 32 * loc = location to use for error printing 33 */ 34 void scanMSCoffObjModule(void delegate(const(char)[] name, int pickAny) pAddSymbol, 35 const(ubyte)[] base, const(char)* module_name, Loc loc) 36 { 37 static if (LOG) 38 { 39 printf("scanMSCoffObjModule(%s)\n", module_name); 40 } 41 42 void corrupt(int reason) 43 { 44 error(loc, "corrupt MS-Coff object module `%s` %d", module_name, reason); 45 } 46 47 const buf = base.ptr; 48 const buflen = base.length; 49 /* First do sanity checks on object file 50 */ 51 if (buflen < BIGOBJ_HEADER.sizeof) 52 return corrupt(__LINE__); 53 54 BIGOBJ_HEADER* header = cast(BIGOBJ_HEADER*)buf; 55 char is_old_coff = false; 56 if (header.Sig2 != 0xFFFF && header.Version != 2) 57 { 58 is_old_coff = true; 59 IMAGE_FILE_HEADER* header_old; 60 header_old = cast(IMAGE_FILE_HEADER*)Mem.check(malloc(IMAGE_FILE_HEADER.sizeof)); 61 memcpy(header_old, buf, IMAGE_FILE_HEADER.sizeof); 62 header = cast(BIGOBJ_HEADER*)Mem.check(malloc(BIGOBJ_HEADER.sizeof)); 63 *header = BIGOBJ_HEADER.init; 64 header.Machine = header_old.Machine; 65 header.NumberOfSections = header_old.NumberOfSections; 66 header.TimeDateStamp = header_old.TimeDateStamp; 67 header.PointerToSymbolTable = header_old.PointerToSymbolTable; 68 header.NumberOfSymbols = header_old.NumberOfSymbols; 69 free(header_old); 70 } 71 switch (header.Machine) 72 { 73 case IMAGE_FILE_MACHINE_UNKNOWN: 74 case IMAGE_FILE_MACHINE_I386: 75 case IMAGE_FILE_MACHINE_AMD64: 76 break; 77 default: 78 if (buf[0] == 0x80) 79 error(loc, "Object module `%s` is 32 bit OMF, but it should be 64 bit MS-Coff", module_name); 80 else 81 error(loc, "MS-Coff object module `%s` has magic = %x, should be %x", module_name, header.Machine, IMAGE_FILE_MACHINE_AMD64); 82 return; 83 } 84 // Get string table: string_table[0..string_len] 85 size_t off = header.PointerToSymbolTable; 86 if (off == 0) 87 { 88 error(loc, "MS-Coff object module `%s` has no string table", module_name); 89 return; 90 } 91 off += header.NumberOfSymbols * (is_old_coff ? SymbolTable.sizeof : SymbolTable32.sizeof); 92 if (off + 4 > buflen) 93 return corrupt(__LINE__); 94 95 uint string_len = *cast(uint*)(buf + off); 96 char* string_table = cast(char*)(buf + off + 4); 97 if (off + string_len > buflen) 98 return corrupt(__LINE__); 99 100 string_len -= 4; 101 for (int i = 0; i < header.NumberOfSymbols; i++) 102 { 103 SymbolTable32* n; 104 char[8 + 1] s; 105 char* p; 106 static if (LOG) 107 { 108 printf("Symbol %d:\n", i); 109 } 110 off = header.PointerToSymbolTable + i * (is_old_coff ? SymbolTable.sizeof : SymbolTable32.sizeof); 111 if (off > buflen) 112 return corrupt(__LINE__); 113 114 n = cast(SymbolTable32*)(buf + off); 115 if (is_old_coff) 116 { 117 SymbolTable* n2; 118 n2 = cast(SymbolTable*)Mem.check(malloc(SymbolTable.sizeof)); 119 memcpy(n2, (buf + off), SymbolTable.sizeof); 120 n = cast(SymbolTable32*)Mem.check(malloc(SymbolTable32.sizeof)); 121 memcpy(n, n2, (n2.Name).sizeof); 122 n.Value = n2.Value; 123 n.SectionNumber = n2.SectionNumber; 124 n.Type = n2.Type; 125 n.StorageClass = n2.StorageClass; 126 n.NumberOfAuxSymbols = n2.NumberOfAuxSymbols; 127 free(n2); 128 } 129 if (n.Zeros) 130 { 131 strncpy(s.ptr, cast(const(char)*)n.Name, 8); 132 s[SYMNMLEN] = 0; 133 p = s.ptr; 134 } 135 else 136 p = string_table + n.Offset - 4; 137 i += n.NumberOfAuxSymbols; 138 static if (LOG) 139 { 140 printf("n_name = '%s'\n", p); 141 printf("n_value = x%08lx\n", n.Value); 142 printf("n_scnum = %d\n", n.SectionNumber); 143 printf("n_type = x%04x\n", n.Type); 144 printf("n_sclass = %d\n", n.StorageClass); 145 printf("n_numaux = %d\n", n.NumberOfAuxSymbols); 146 } 147 switch (n.SectionNumber) 148 { 149 case IMAGE_SYM_DEBUG: 150 continue; 151 case IMAGE_SYM_ABSOLUTE: 152 if (strcmp(p, "@comp.id") == 0) 153 continue; 154 break; 155 case IMAGE_SYM_UNDEFINED: 156 // A non-zero value indicates a common block 157 if (n.Value) 158 break; 159 continue; 160 default: 161 break; 162 } 163 switch (n.StorageClass) 164 { 165 case IMAGE_SYM_CLASS_EXTERNAL: 166 break; 167 case IMAGE_SYM_CLASS_STATIC: 168 if (n.Value == 0) // if it's a section name 169 continue; 170 continue; 171 case IMAGE_SYM_CLASS_FUNCTION: 172 case IMAGE_SYM_CLASS_FILE: 173 case IMAGE_SYM_CLASS_LABEL: 174 continue; 175 default: 176 continue; 177 } 178 pAddSymbol(p.toDString(), 1); 179 } 180 } 181 182 private: // for the remainder of this module 183 184 align(1) 185 struct BIGOBJ_HEADER 186 { 187 WORD Sig1; // IMAGE_FILE_MACHINE_UNKNOWN 188 WORD Sig2; // 0xFFFF 189 WORD Version; // 2 190 WORD Machine; // identifies type of target machine 191 DWORD TimeDateStamp; // creation date, number of seconds since 1970 192 BYTE[16] UUID; // { '\xc7', '\xa1', '\xba', '\xd1', '\xee', '\xba', '\xa9', '\x4b', 193 // '\xaf', '\x20', '\xfa', '\xf6', '\x6a', '\xa4', '\xdc', '\xb8' }; 194 DWORD[4] unused; // { 0, 0, 0, 0 } 195 DWORD NumberOfSections; // number of sections 196 DWORD PointerToSymbolTable; // file offset of symbol table 197 DWORD NumberOfSymbols; // number of entries in the symbol table 198 } 199 200 align(1) 201 struct IMAGE_FILE_HEADER 202 { 203 WORD Machine; 204 WORD NumberOfSections; 205 DWORD TimeDateStamp; 206 DWORD PointerToSymbolTable; 207 DWORD NumberOfSymbols; 208 WORD SizeOfOptionalHeader; 209 WORD Characteristics; 210 } 211 212 enum SYMNMLEN = 8; 213 214 enum IMAGE_FILE_MACHINE_UNKNOWN = 0; // applies to any machine type 215 enum IMAGE_FILE_MACHINE_I386 = 0x14C; // x86 216 enum IMAGE_FILE_MACHINE_AMD64 = 0x8664; // x86_64 217 218 enum IMAGE_SYM_DEBUG = -2; 219 enum IMAGE_SYM_ABSOLUTE = -1; 220 enum IMAGE_SYM_UNDEFINED = 0; 221 222 enum IMAGE_SYM_CLASS_EXTERNAL = 2; 223 enum IMAGE_SYM_CLASS_STATIC = 3; 224 enum IMAGE_SYM_CLASS_LABEL = 6; 225 enum IMAGE_SYM_CLASS_FUNCTION = 101; 226 enum IMAGE_SYM_CLASS_FILE = 103; 227 228 align(1) struct SymbolTable32 229 { 230 union 231 { 232 BYTE[SYMNMLEN] Name; 233 struct 234 { 235 DWORD Zeros; 236 DWORD Offset; 237 } 238 } 239 240 DWORD Value; 241 DWORD SectionNumber; 242 WORD Type; 243 BYTE StorageClass; 244 BYTE NumberOfAuxSymbols; 245 } 246 247 align(1) struct SymbolTable 248 { 249 BYTE[SYMNMLEN] Name; 250 DWORD Value; 251 WORD SectionNumber; 252 WORD Type; 253 BYTE StorageClass; 254 BYTE NumberOfAuxSymbols; 255 }