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