1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _scanmach.d) 9 */ 10 11 module ddmd.scanmach; 12 13 import core.stdc..string; 14 import core.stdc.stdint; 15 import core.sys.osx.mach.loader; 16 import ddmd.globals; 17 import ddmd.errors; 18 19 enum LOG = false; 20 21 /***************************************** 22 * Reads an object module from base[] and passes the names 23 * of any exported symbols to (*pAddSymbol)(). 24 * Params: 25 * pAddSymbol = function to pass the names to 26 * base = array of contents of object module 27 * module_name = name of the object module (used for error messages) 28 * loc = location to use for error printing 29 */ 30 void scanMachObjModule(void delegate(const(char)[] name, int pickAny) pAddSymbol, 31 const(ubyte)[] base, const(char)* module_name, Loc loc) 32 { 33 static if (LOG) 34 { 35 printf("scanMachObjModule(%s)\n", module_name); 36 } 37 38 void corrupt(int reason) 39 { 40 error(loc, "corrupt Mach-O object module %s %d", module_name, reason); 41 } 42 43 const buf = base.ptr; 44 const buflen = base.length; 45 uint32_t ncmds; 46 mach_header* header = cast(mach_header*)buf; 47 mach_header_64* header64 = null; 48 /* First do sanity checks on object file 49 */ 50 if (buflen < mach_header.sizeof) 51 return corrupt(__LINE__); 52 53 if (header.magic == MH_MAGIC) 54 { 55 if (header.cputype != CPU_TYPE_I386) 56 { 57 error(loc, "Mach-O object module %s has cputype = %d, should be %d", module_name, header.cputype, CPU_TYPE_I386); 58 return; 59 } 60 if (header.filetype != MH_OBJECT) 61 { 62 error(loc, "Mach-O object module %s has file type = %d, should be %d", module_name, header.filetype, MH_OBJECT); 63 return; 64 } 65 if (buflen < mach_header.sizeof + header.sizeofcmds) 66 return corrupt(__LINE__); 67 ncmds = header.ncmds; 68 } 69 else if (header.magic == MH_MAGIC_64) 70 { 71 header64 = cast(mach_header_64*)buf; 72 if (buflen < mach_header_64.sizeof) 73 return corrupt(__LINE__); 74 if (header64.cputype != CPU_TYPE_X86_64) 75 { 76 error(loc, "Mach-O object module %s has cputype = %d, should be %d", module_name, header64.cputype, CPU_TYPE_X86_64); 77 return; 78 } 79 if (header64.filetype != MH_OBJECT) 80 { 81 error(loc, "Mach-O object module %s has file type = %d, should be %d", module_name, header64.filetype, MH_OBJECT); 82 return; 83 } 84 if (buflen < mach_header_64.sizeof + header64.sizeofcmds) 85 return corrupt(__LINE__); 86 ncmds = header64.ncmds; 87 } 88 else 89 return corrupt(__LINE__); 90 91 segment_command* segment_commands = null; 92 segment_command_64* segment_commands64 = null; 93 symtab_command* symtab_commands = null; 94 dysymtab_command* dysymtab_commands = null; 95 // Commands immediately follow mach_header 96 char* commands = cast(char*)buf + (header.magic == MH_MAGIC_64 ? mach_header_64.sizeof : mach_header.sizeof); 97 for (uint32_t i = 0; i < ncmds; i++) 98 { 99 load_command* command = cast(load_command*)commands; 100 //printf("cmd = 0x%02x, cmdsize = %u\n", command->cmd, command->cmdsize); 101 switch (command.cmd) 102 { 103 case LC_SEGMENT: 104 segment_commands = cast(segment_command*)command; 105 break; 106 case LC_SEGMENT_64: 107 segment_commands64 = cast(segment_command_64*)command; 108 break; 109 case LC_SYMTAB: 110 symtab_commands = cast(symtab_command*)command; 111 break; 112 case LC_DYSYMTAB: 113 dysymtab_commands = cast(dysymtab_command*)command; 114 break; 115 default: 116 break; 117 } 118 commands += command.cmdsize; 119 } 120 if (symtab_commands) 121 { 122 // Get pointer to string table 123 char* strtab = cast(char*)buf + symtab_commands.stroff; 124 if (buflen < symtab_commands.stroff + symtab_commands.strsize) 125 return corrupt(__LINE__); 126 127 if (header.magic == MH_MAGIC_64) 128 { 129 // Get pointer to symbol table 130 nlist_64* symtab = cast(nlist_64*)(cast(char*)buf + symtab_commands.symoff); 131 if (buflen < symtab_commands.symoff + symtab_commands.nsyms * nlist_64.sizeof) 132 return corrupt(__LINE__); 133 134 // For each symbol 135 for (int i = 0; i < symtab_commands.nsyms; i++) 136 { 137 nlist_64* s = symtab + i; 138 const(char)* name = strtab + s.n_strx; 139 const namelen = strlen(name); 140 if (s.n_type & N_STAB) 141 { 142 // values in /usr/include/mach-o/stab.h 143 //printf(" N_STAB"); 144 } 145 else 146 { 147 version (none) 148 { 149 if (s.n_type & N_PEXT) 150 { 151 } 152 if (s.n_type & N_EXT) 153 { 154 } 155 } 156 switch (s.n_type & N_TYPE) 157 { 158 case N_UNDF: 159 if (s.n_type & N_EXT && s.n_value != 0) // comdef 160 pAddSymbol(name[0 .. namelen], 1); 161 break; 162 case N_ABS: 163 break; 164 case N_SECT: 165 if (s.n_type & N_EXT) /*&& !(s->n_desc & N_REF_TO_WEAK)*/ 166 pAddSymbol(name[0 .. namelen], 1); 167 break; 168 case N_PBUD: 169 break; 170 case N_INDR: 171 break; 172 default: 173 break; 174 } 175 } 176 } 177 } 178 else 179 { 180 // Get pointer to symbol table 181 nlist* symtab = cast(nlist*)(cast(char*)buf + symtab_commands.symoff); 182 if (buflen < symtab_commands.symoff + symtab_commands.nsyms * nlist.sizeof) 183 return corrupt(__LINE__); 184 185 // For each symbol 186 for (int i = 0; i < symtab_commands.nsyms; i++) 187 { 188 nlist* s = symtab + i; 189 const(char)* name = strtab + s.n_strx; 190 const namelen = strlen(name); 191 if (s.n_type & N_STAB) 192 { 193 // values in /usr/include/mach-o/stab.h 194 //printf(" N_STAB"); 195 } 196 else 197 { 198 version (none) 199 { 200 if (s.n_type & N_PEXT) 201 { 202 } 203 if (s.n_type & N_EXT) 204 { 205 } 206 } 207 switch (s.n_type & N_TYPE) 208 { 209 case N_UNDF: 210 if (s.n_type & N_EXT && s.n_value != 0) // comdef 211 pAddSymbol(name[0 .. namelen], 1); 212 break; 213 case N_ABS: 214 break; 215 case N_SECT: 216 if (s.n_type & N_EXT) /*&& !(s->n_desc & N_REF_TO_WEAK)*/ 217 pAddSymbol(name[0 .. namelen], 1); 218 break; 219 case N_PBUD: 220 break; 221 case N_INDR: 222 break; 223 default: 224 break; 225 } 226 } 227 } 228 } 229 } 230 } 231 232 enum CPU_TYPE_I386 = 7; 233 enum CPU_TYPE_X86_64 = CPU_TYPE_I386 | 0x1000000; 234 235 enum MH_OBJECT = 0x1; 236 237 struct segment_command 238 { 239 uint32_t cmd; 240 uint32_t cmdsize; 241 char[16] segname; 242 uint32_t vmaddr; 243 uint32_t vmsize; 244 uint32_t fileoff; 245 uint32_t filesize; 246 int32_t maxprot; 247 int32_t initprot; 248 uint32_t nsects; 249 uint32_t flags; 250 } 251 252 struct segment_command_64 253 { 254 uint32_t cmd; 255 uint32_t cmdsize; 256 char[16] segname; 257 uint64_t vmaddr; 258 uint64_t vmsize; 259 uint64_t fileoff; 260 uint64_t filesize; 261 int32_t maxprot; 262 int32_t initprot; 263 uint32_t nsects; 264 uint32_t flags; 265 } 266 267 struct symtab_command 268 { 269 uint32_t cmd; 270 uint32_t cmdsize; 271 uint32_t symoff; 272 uint32_t nsyms; 273 uint32_t stroff; 274 uint32_t strsize; 275 } 276 277 struct dysymtab_command 278 { 279 uint32_t cmd; 280 uint32_t cmdsize; 281 uint32_t ilocalsym; 282 uint32_t nlocalsym; 283 uint32_t iextdefsym; 284 uint32_t nextdefsym; 285 uint32_t iundefsym; 286 uint32_t nundefsym; 287 uint32_t tocoff; 288 uint32_t ntoc; 289 uint32_t modtaboff; 290 uint32_t nmodtab; 291 uint32_t extrefsymoff; 292 uint32_t nextrefsyms; 293 uint32_t indirectsymoff; 294 uint32_t nindirectsyms; 295 uint32_t extreloff; 296 uint32_t nextrel; 297 uint32_t locreloff; 298 uint32_t nlocrel; 299 } 300 301 enum LC_SEGMENT = 1; 302 enum LC_SYMTAB = 2; 303 enum LC_DYSYMTAB = 11; 304 enum LC_SEGMENT_64 = 0x19; 305 306 struct load_command 307 { 308 uint32_t cmd; 309 uint32_t cmdsize; 310 } 311 312 enum N_EXT = 1; 313 enum N_STAB = 0xE0; 314 enum N_PEXT = 0x10; 315 enum N_TYPE = 0x0E; 316 enum N_UNDF = 0; 317 enum N_ABS = 2; 318 enum N_INDR = 10; 319 enum N_PBUD = 12; 320 enum N_SECT = 14; 321 322 struct nlist 323 { 324 int32_t n_strx; 325 uint8_t n_type; 326 uint8_t n_sect; 327 int16_t n_desc; 328 uint32_t n_value; 329 } 330 331 struct nlist_64 332 { 333 uint32_t n_strx; 334 uint8_t n_type; 335 uint8_t n_sect; 336 uint16_t n_desc; 337 uint64_t n_value; 338 }