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