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 _scanomf.d) 9 */ 10 11 module ddmd.scanomf; 12 13 import core.stdc..string; 14 import core.stdc.stdlib; 15 import ddmd.globals; 16 import ddmd.root.outbuffer; 17 import ddmd.arraytypes; 18 import ddmd.errors; 19 20 enum LOG = false; 21 22 /************************** 23 * Record types: 24 */ 25 enum RHEADR = 0x6E; 26 enum REGINT = 0x70; 27 enum REDATA = 0x72; 28 enum RIDATA = 0x74; 29 enum OVLDEF = 0x76; 30 enum ENDREC = 0x78; 31 enum BLKDEF = 0x7A; 32 enum BLKEND = 0x7C; 33 enum DEBSYM = 0x7E; 34 enum THEADR = 0x80; 35 enum LHEADR = 0x82; 36 enum PEDATA = 0x84; 37 enum PIDATA = 0x86; 38 enum COMENT = 0x88; 39 enum MODEND = 0x8A; 40 enum M386END = 0x8B; /* 32 bit module end record */ 41 enum EXTDEF = 0x8C; 42 enum TYPDEF = 0x8E; 43 enum PUBDEF = 0x90; 44 enum PUB386 = 0x91; 45 enum LOCSYM = 0x92; 46 enum LINNUM = 0x94; 47 enum LNAMES = 0x96; 48 enum SEGDEF = 0x98; 49 enum GRPDEF = 0x9A; 50 enum FIXUPP = 0x9C; 51 /*#define (none) 0x9E */ 52 enum LEDATA = 0xA0; 53 enum LIDATA = 0xA2; 54 enum LIBHED = 0xA4; 55 enum LIBNAM = 0xA6; 56 enum LIBLOC = 0xA8; 57 enum LIBDIC = 0xAA; 58 enum COMDEF = 0xB0; 59 enum LEXTDEF = 0xB4; 60 enum LPUBDEF = 0xB6; 61 enum LCOMDEF = 0xB8; 62 enum CEXTDEF = 0xBC; 63 enum COMDAT = 0xC2; 64 enum LINSYM = 0xC4; 65 enum ALIAS = 0xC6; 66 enum LLNAMES = 0xCA; 67 enum LIBIDMAX = (512 - 0x25 - 3 - 4); 68 69 // max size that will fit in dictionary 70 extern (C++) void parseName(const(ubyte)** pp, char* name) 71 { 72 auto p = *pp; 73 uint len = *p++; 74 if (len == 0xFF && *p == 0) // if long name 75 { 76 len = p[1] & 0xFF; 77 len |= cast(uint)p[2] << 8; 78 p += 3; 79 assert(len <= LIBIDMAX); 80 } 81 memcpy(name, p, len); 82 name[len] = 0; 83 *pp = p + len; 84 } 85 86 extern (C++) static ushort parseIdx(const(ubyte)** pp) 87 { 88 auto p = *pp; 89 const c = *p++; 90 ushort idx = (0x80 & c) ? ((0x7F & c) << 8) + *p++ : c; 91 *pp = p; 92 return idx; 93 } 94 95 // skip numeric field of a data type of a COMDEF record 96 extern (C++) static void skipNumericField(const(ubyte)** pp) 97 { 98 const(ubyte)* p = *pp; 99 const c = *p++; 100 if (c == 0x81) 101 p += 2; 102 else if (c == 0x84) 103 p += 3; 104 else if (c == 0x88) 105 p += 4; 106 else 107 assert(c <= 0x80); 108 *pp = p; 109 } 110 111 // skip data type of a COMDEF record 112 extern (C++) static void skipDataType(const(ubyte)** pp) 113 { 114 auto p = *pp; 115 const c = *p++; 116 if (c == 0x61) 117 { 118 // FAR data 119 skipNumericField(&p); 120 skipNumericField(&p); 121 } 122 else if (c == 0x62) 123 { 124 // NEAR data 125 skipNumericField(&p); 126 } 127 else 128 { 129 assert(1 <= c && c <= 0x5f); // Borland segment indices 130 } 131 *pp = p; 132 } 133 134 /***************************************** 135 * Reads an object module from base[] and passes the names 136 * of any exported symbols to (*pAddSymbol)(). 137 * Params: 138 * pAddSymbol = function to pass the names to 139 * base = array of contents of object module 140 * module_name = name of the object module (used for error messages) 141 * loc = location to use for error printing 142 */ 143 void scanOmfObjModule(void delegate(const(char)[] name, int pickAny) pAddSymbol, 144 const(ubyte)[] base, const(char)* module_name, Loc loc) 145 { 146 static if (LOG) 147 { 148 printf("scanOmfObjModule(%s)\n", module_name); 149 } 150 const buf = base.ptr; 151 const buflen = base.length; 152 int easyomf; 153 ubyte result = 0; 154 char[LIBIDMAX + 1] name; 155 Strings names; 156 names.push(null); // don't use index 0 157 easyomf = 0; // assume not EASY-OMF 158 auto pend = cast(const(ubyte)*)base.ptr + buflen; 159 const(ubyte)* pnext; 160 for (auto p = cast(const(ubyte)*)base.ptr; 1; p = pnext) 161 { 162 assert(p < pend); 163 ubyte recTyp = *p++; 164 ushort recLen = *cast(ushort*)p; 165 p += 2; 166 pnext = p + recLen; 167 recLen--; // forget the checksum 168 switch (recTyp) 169 { 170 case LNAMES: 171 case LLNAMES: 172 while (p + 1 < pnext) 173 { 174 parseName(&p, name.ptr); 175 names.push(strdup(name.ptr)); 176 } 177 break; 178 case PUBDEF: 179 if (easyomf) 180 recTyp = PUB386; // convert to MS format 181 goto case; 182 case PUB386: 183 if (!(parseIdx(&p) | parseIdx(&p))) 184 p += 2; // skip seg, grp, frame 185 while (p + 1 < pnext) 186 { 187 parseName(&p, name.ptr); 188 p += (recTyp == PUBDEF) ? 2 : 4; // skip offset 189 parseIdx(&p); // skip type index 190 pAddSymbol(name[0 .. strlen(name.ptr)], 0); 191 } 192 break; 193 case COMDAT: 194 if (easyomf) 195 recTyp = COMDAT + 1; // convert to MS format 196 goto case; 197 case COMDAT + 1: 198 { 199 int pickAny = 0; 200 if (*p++ & 5) // if continuation or local comdat 201 break; 202 ubyte attr = *p++; 203 if (attr & 0xF0) // attr: if multiple instances allowed 204 pickAny = 1; 205 p++; // align 206 p += 2; // enum data offset 207 if (recTyp == COMDAT + 1) 208 p += 2; // enum data offset 209 parseIdx(&p); // type index 210 if ((attr & 0x0F) == 0) // if explicit allocation 211 { 212 parseIdx(&p); // base group 213 parseIdx(&p); // base segment 214 } 215 uint idx = parseIdx(&p); // public name index 216 if (idx == 0 || idx >= names.dim) 217 { 218 //debug(printf("[s] name idx=%d, uCntNames=%d\n", idx, uCntNames)); 219 error(loc, "corrupt COMDAT"); 220 return; 221 } 222 //printf("[s] name='%s'\n",name); 223 const(char)* n = names[idx]; 224 pAddSymbol(n[0 .. strlen(name.ptr)], pickAny); 225 break; 226 } 227 case COMDEF: 228 { 229 while (p + 1 < pnext) 230 { 231 parseName(&p, name.ptr); 232 parseIdx(&p); // type index 233 skipDataType(&p); // data type 234 pAddSymbol(name[0 .. strlen(name.ptr)], 1); 235 } 236 break; 237 } 238 case ALIAS: 239 while (p + 1 < pnext) 240 { 241 parseName(&p, name.ptr); 242 pAddSymbol(name[0 .. strlen(name.ptr)], 0); 243 parseName(&p, name.ptr); 244 } 245 break; 246 case MODEND: 247 case M386END: 248 result = 1; 249 goto Ret; 250 case COMENT: 251 // Recognize Phar Lap EASY-OMF format 252 { 253 static __gshared ubyte* omfstr1 = [0x80, 0xAA, '8', '0', '3', '8', '6']; 254 if (recLen == (omfstr1).sizeof) 255 { 256 for (uint i = 0; i < (omfstr1).sizeof; i++) 257 if (*p++ != omfstr1[i]) 258 goto L1; 259 easyomf = 1; 260 break; 261 L1: 262 } 263 } 264 // Recognize .IMPDEF Import Definition Records 265 { 266 static __gshared ubyte* omfstr2 = [0, 0xA0, 1]; 267 if (recLen >= 7) 268 { 269 p++; 270 for (uint i = 1; i < (omfstr2).sizeof; i++) 271 if (*p++ != omfstr2[i]) 272 goto L2; 273 p++; // skip OrdFlag field 274 parseName(&p, name.ptr); 275 pAddSymbol(name[0 .. strlen(name.ptr)], 0); 276 break; 277 L2: 278 } 279 } 280 break; 281 default: 282 // ignore 283 } 284 } 285 Ret: 286 for (size_t u = 1; u < names.dim; u++) 287 free(cast(void*)names[u]); 288 } 289 290 /************************************************* 291 * Scan a block of memory buf[0..buflen], pulling out each 292 * OMF object module in it and sending the info in it to (*pAddObjModule). 293 * Returns: 294 * true for corrupt OMF data 295 */ 296 bool scanOmfLib(void delegate(char* name, void* base, size_t length) pAddObjModule, void* buf, size_t buflen, uint pagesize) 297 { 298 /* Split up the buffer buf[0..buflen] into multiple object modules, 299 * each aligned on a pagesize boundary. 300 */ 301 bool first_module = true; 302 const(ubyte)* base = null; 303 char[LIBIDMAX + 1] name; 304 auto p = cast(const(ubyte)*)buf; 305 auto pend = p + buflen; 306 const(ubyte)* pnext; 307 for (; p < pend; p = pnext) // for each OMF record 308 { 309 if (p + 3 >= pend) 310 return true; // corrupt 311 ubyte recTyp = *p; 312 ushort recLen = *cast(const(ushort)*)(p + 1); 313 pnext = p + 3 + recLen; 314 if (pnext > pend) 315 return true; // corrupt 316 recLen--; // forget the checksum 317 switch (recTyp) 318 { 319 case LHEADR: 320 case THEADR: 321 if (!base) 322 { 323 base = p; 324 p += 3; 325 parseName(&p, name.ptr); 326 if (name[0] == 'C' && name[1] == 0) // old C compilers did this 327 base = pnext; // skip past THEADR 328 } 329 break; 330 case MODEND: 331 case M386END: 332 { 333 if (base) 334 { 335 pAddObjModule(name.ptr, cast(ubyte*)base, pnext - base); 336 base = null; 337 } 338 // Round up to next page 339 uint t = cast(uint)(pnext - cast(const(ubyte)*)buf); 340 t = (t + pagesize - 1) & ~cast(uint)(pagesize - 1); 341 pnext = cast(const(ubyte)*)buf + t; 342 break; 343 } 344 default: 345 // ignore 346 } 347 } 348 return (base !is null); // missing MODEND record 349 } 350 351 uint OMFObjSize(const(void)* base, uint length, const(char)* name) 352 { 353 ubyte c = *cast(const(ubyte)*)base; 354 if (c != THEADR && c != LHEADR) 355 { 356 size_t len = strlen(name); 357 assert(len <= LIBIDMAX); 358 length += len + 5; 359 } 360 return length; 361 } 362 363 void writeOMFObj(OutBuffer* buf, const(void)* base, uint length, const(char)* name) 364 { 365 ubyte c = *cast(const(ubyte)*)base; 366 if (c != THEADR && c != LHEADR) 367 { 368 const len = strlen(name); 369 assert(len <= LIBIDMAX); 370 ubyte[4 + LIBIDMAX + 1] header; 371 header[0] = THEADR; 372 header[1] = cast(ubyte)(2 + len); 373 header[2] = 0; 374 header[3] = cast(ubyte)len; 375 assert(len <= 0xFF - 2); 376 memcpy(4 + header.ptr, name, len); 377 // Compute and store record checksum 378 uint n = cast(uint)(len + 4); 379 ubyte checksum = 0; 380 ubyte* p = header.ptr; 381 while (n--) 382 { 383 checksum -= *p; 384 p++; 385 } 386 *p = checksum; 387 buf.write(header.ptr, len + 5); 388 } 389 buf.write(base, length); 390 }