1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) 2012-2021 by The D Language Foundation, 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: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cv8.d, backend/cv8.d) 9 */ 10 11 // This module generates the .debug$S and .debug$T sections for Win64, 12 // which are the MS-Coff symbolic debug info and type debug info sections. 13 14 module dmd.backend.cv8; 15 16 version (MARS) 17 version = COMPILE; 18 version (SCPP) 19 version = COMPILE; 20 21 version (COMPILE) 22 { 23 24 import core.stdc.stdio; 25 import core.stdc.stdlib; 26 import core.stdc.string; 27 extern (C) nothrow char* getcwd(char*, size_t); 28 29 import dmd.backend.cc; 30 import dmd.backend.cdef; 31 import dmd.backend.cgcv; 32 import dmd.backend.code; 33 import dmd.backend.code_x86; 34 import dmd.backend.cv4; 35 import dmd.backend.mem; 36 import dmd.backend.el; 37 import dmd.backend.exh; 38 import dmd.backend.global; 39 import dmd.backend.obj; 40 import dmd.backend.oper; 41 import dmd.backend.outbuf; 42 import dmd.backend.rtlsym; 43 import dmd.backend.ty; 44 import dmd.backend.type; 45 import dmd.backend.dvarstats; 46 import dmd.backend.xmm; 47 48 extern (C++): 49 50 nothrow: 51 52 static if (1) 53 { 54 55 int REGSIZE(); 56 57 // Determine if this Symbol is stored in a COMDAT 58 private bool symbol_iscomdat4(Symbol* s) 59 { 60 version (MARS) 61 { 62 return s.Sclass == SCcomdat || 63 config.flags2 & CFG2comdat && s.Sclass == SCinline || 64 config.flags4 & CFG4allcomdat && s.Sclass == SCglobal; 65 } 66 else 67 { 68 return s.Sclass == SCcomdat || 69 config.flags2 & CFG2comdat && s.Sclass == SCinline || 70 config.flags4 & CFG4allcomdat && (s.Sclass == SCglobal || s.Sclass == SCstatic); 71 } 72 } 73 74 75 // if symbols get longer than 65500 bytes, the linker reports corrupt debug info or exits with 76 // 'fatal error LNK1318: Unexpected PDB error; RPC (23) '(0x000006BA)' 77 enum CV8_MAX_SYMBOL_LENGTH = 0xffd8; 78 79 // The "F1" section, which is the symbols 80 private __gshared Outbuffer *F1_buf; 81 82 // The "F2" section, which is the line numbers 83 private __gshared Outbuffer *F2_buf; 84 85 // The "F3" section, which is global and a string table of source file names. 86 private __gshared Outbuffer *F3_buf; 87 88 // The "F4" section, which is global and a lists info about source files. 89 private __gshared Outbuffer *F4_buf; 90 91 /* Fixups that go into F1 section 92 */ 93 struct F1_Fixups 94 { 95 Symbol *s; 96 uint offset; 97 uint value; 98 } 99 100 private __gshared Outbuffer *F1fixup; // array of F1_Fixups 101 102 /* Struct in which to collect per-function data, for later emission 103 * into .debug$S. 104 */ 105 struct FuncData 106 { 107 Symbol *sfunc; 108 uint section_length; 109 const(char)* srcfilename; 110 uint srcfileoff; 111 uint linepairstart; // starting byte index of offset/line pairs in linebuf[] 112 uint linepairbytes; // number of bytes for offset/line pairs 113 uint linepairsegment; // starting byte index of filename segment for offset/line pairs 114 Outbuffer *f1buf; 115 Outbuffer *f1fixup; 116 } 117 118 __gshared FuncData currentfuncdata; 119 120 private __gshared Outbuffer *funcdata; // array of FuncData's 121 122 private __gshared Outbuffer *linepair; // array of offset/line pairs 123 124 void cv8_writename(Outbuffer *buf, const(char)* name, size_t len) 125 { 126 if(config.flags2 & CFG2gms) 127 { 128 const(char)* start = name; 129 const(char)* cur = strchr(start, '.'); 130 const(char)* end = start + len; 131 while(cur != null) 132 { 133 if(cur >= end) 134 { 135 buf.writen(start, end - start); 136 return; 137 } 138 buf.writen(start, cur - start); 139 buf.writeByte('@'); 140 start = cur + 1; 141 if(start >= end) 142 return; 143 cur = strchr(start, '.'); 144 } 145 buf.writen(start, end - start); 146 } 147 else 148 buf.writen(name, len); 149 } 150 151 /************************************************ 152 * Called at the start of an object file generation. 153 * One source file can generate multiple object files; this starts an object file. 154 * Input: 155 * filename source file name 156 */ 157 void cv8_initfile(const(char)* filename) 158 { 159 //printf("cv8_initfile()\n"); 160 161 // Recycle buffers; much faster than delete/renew 162 163 if (!F1_buf) 164 { 165 __gshared Outbuffer f1buf; 166 f1buf.reserve(1024); 167 F1_buf = &f1buf; 168 } 169 F1_buf.reset(); 170 171 if (!F1fixup) 172 { 173 __gshared Outbuffer f1fixupbuf; 174 f1fixupbuf.reserve(1024); 175 F1fixup = &f1fixupbuf; 176 } 177 F1fixup.reset(); 178 179 if (!F2_buf) 180 { 181 __gshared Outbuffer f2buf; 182 f2buf.reserve(1024); 183 F2_buf = &f2buf; 184 } 185 F2_buf.reset(); 186 187 if (!F3_buf) 188 { 189 __gshared Outbuffer f3buf; 190 f3buf.reserve(1024); 191 F3_buf = &f3buf; 192 } 193 F3_buf.reset(); 194 F3_buf.writeByte(0); // first "filename" 195 196 if (!F4_buf) 197 { 198 __gshared Outbuffer f4buf; 199 f4buf.reserve(1024); 200 F4_buf = &f4buf; 201 } 202 F4_buf.reset(); 203 204 if (!funcdata) 205 { 206 __gshared Outbuffer funcdatabuf; 207 funcdatabuf.reserve(1024); 208 funcdata = &funcdatabuf; 209 } 210 funcdata.reset(); 211 212 if (!linepair) 213 { 214 __gshared Outbuffer linepairbuf; 215 linepairbuf.reserve(1024); 216 linepair = &linepairbuf; 217 } 218 linepair.reset(); 219 220 memset(¤tfuncdata, 0, currentfuncdata.sizeof); 221 currentfuncdata.f1buf = F1_buf; 222 currentfuncdata.f1fixup = F1fixup; 223 224 cv_init(); 225 } 226 227 void cv8_termfile(const(char)* objfilename) 228 { 229 //printf("cv8_termfile()\n"); 230 231 /* Write out the debug info sections. 232 */ 233 234 int seg = MsCoffObj_seg_debugS(); 235 236 uint value = 4; 237 objmod.bytes(seg,0,4,&value); 238 239 /* Start with starting symbol in separate "F1" section 240 */ 241 Outbuffer buf = Outbuffer(1024); 242 size_t len = strlen(objfilename); 243 buf.write16(cast(int)(2 + 4 + len + 1)); 244 buf.write16(S_COMPILAND_V3); 245 buf.write32(0); 246 buf.write(objfilename, cast(uint)(len + 1)); 247 248 // write S_COMPILE record 249 buf.write16(2 + 1 + 1 + 2 + 1 + VERSION.length + 1); 250 buf.write16(S_COMPILE); 251 buf.writeByte(I64 ? 0xD0 : 6); // target machine AMD64 or x86 (Pentium II) 252 buf.writeByte(config.flags2 & CFG2gms ? (CPP != 0) : 'D'); // language index (C/C++/D) 253 buf.write16(0x800 | (config.inline8087 ? 0 : (1<<3))); // 32-bit, float package 254 buf.writeByte(VERSION.length + 1); 255 buf.writeByte('Z'); 256 buf.write(VERSION.ptr, VERSION.length); 257 258 cv8_writesection(seg, 0xF1, &buf); 259 260 // Write out "F2" sections 261 uint length = cast(uint)funcdata.length(); 262 ubyte *p = funcdata.buf; 263 for (uint u = 0; u < length; u += FuncData.sizeof) 264 { FuncData *fd = cast(FuncData *)(p + u); 265 266 F2_buf.reset(); 267 268 F2_buf.write32(cast(uint)fd.sfunc.Soffset); 269 F2_buf.write32(0); 270 F2_buf.write32(fd.section_length); 271 F2_buf.write(linepair.buf + fd.linepairstart, fd.linepairbytes); 272 273 int f2seg = seg; 274 if (symbol_iscomdat4(fd.sfunc)) 275 { 276 f2seg = MsCoffObj_seg_debugS_comdat(fd.sfunc); 277 objmod.bytes(f2seg, 0, 4, &value); 278 } 279 280 uint offset = cast(uint)SegData[f2seg].SDoffset + 8; 281 cv8_writesection(f2seg, 0xF2, F2_buf); 282 objmod.reftoident(f2seg, offset, fd.sfunc, 0, CFseg | CFoff); 283 284 if (f2seg != seg && fd.f1buf.length()) 285 { 286 // Write out "F1" section 287 const uint f1offset = cast(uint)SegData[f2seg].SDoffset; 288 cv8_writesection(f2seg, 0xF1, fd.f1buf); 289 290 // Fixups for "F1" section 291 const uint fixupLength = cast(uint)fd.f1fixup.length(); 292 ubyte *pfixup = fd.f1fixup.buf; 293 for (uint v = 0; v < fixupLength; v += F1_Fixups.sizeof) 294 { F1_Fixups *f = cast(F1_Fixups *)(pfixup + v); 295 296 objmod.reftoident(f2seg, f1offset + 8 + f.offset, f.s, f.value, CFseg | CFoff); 297 } 298 } 299 } 300 301 // Write out "F3" section 302 if (F3_buf.length() > 1) 303 cv8_writesection(seg, 0xF3, F3_buf); 304 305 // Write out "F4" section 306 if (F4_buf.length() > 0) 307 cv8_writesection(seg, 0xF4, F4_buf); 308 309 if (F1_buf.length()) 310 { 311 // Write out "F1" section 312 uint f1offset = cast(uint)SegData[seg].SDoffset; 313 cv8_writesection(seg, 0xF1, F1_buf); 314 315 // Fixups for "F1" section 316 length = cast(uint)F1fixup.length(); 317 p = F1fixup.buf; 318 for (uint u = 0; u < length; u += F1_Fixups.sizeof) 319 { F1_Fixups *f = cast(F1_Fixups *)(p + u); 320 321 objmod.reftoident(seg, f1offset + 8 + f.offset, f.s, f.value, CFseg | CFoff); 322 } 323 } 324 325 // Write out .debug$T section 326 cv_term(); 327 } 328 329 /************************************************ 330 * Called at the start of a module. 331 * Note that there can be multiple modules in one object file. 332 * cv8_initfile() must be called first. 333 */ 334 void cv8_initmodule(const(char)* filename, const(char)* modulename) 335 { 336 //printf("cv8_initmodule(filename = %s, modulename = %s)\n", filename, modulename); 337 } 338 339 void cv8_termmodule() 340 { 341 //printf("cv8_termmodule()\n"); 342 assert(config.objfmt == OBJ_MSCOFF); 343 } 344 345 /****************************************** 346 * Called at the start of a function. 347 */ 348 void cv8_func_start(Symbol *sfunc) 349 { 350 //printf("cv8_func_start(%s)\n", sfunc.Sident); 351 currentfuncdata.sfunc = sfunc; 352 currentfuncdata.section_length = 0; 353 currentfuncdata.srcfilename = null; 354 currentfuncdata.linepairstart += currentfuncdata.linepairbytes; 355 currentfuncdata.linepairbytes = 0; 356 currentfuncdata.f1buf = F1_buf; 357 currentfuncdata.f1fixup = F1fixup; 358 if (symbol_iscomdat4(sfunc)) 359 { 360 // This leaks memory 361 currentfuncdata.f1buf = cast(Outbuffer*)mem_calloc(Outbuffer.sizeof); 362 currentfuncdata.f1buf.reserve(128); 363 currentfuncdata.f1fixup = cast(Outbuffer*)mem_calloc(Outbuffer.sizeof); 364 currentfuncdata.f1fixup.reserve(128); 365 } 366 367 varStats_startFunction(); 368 } 369 370 void cv8_func_term(Symbol *sfunc) 371 { 372 //printf("cv8_func_term(%s)\n", sfunc.Sident); 373 374 assert(currentfuncdata.sfunc == sfunc); 375 currentfuncdata.section_length = cast(uint)sfunc.Ssize; 376 377 funcdata.write(¤tfuncdata, currentfuncdata.sizeof); 378 379 // Write function symbol 380 assert(tyfunc(sfunc.ty())); 381 idx_t typidx; 382 func_t* fn = sfunc.Sfunc; 383 if(fn.Fclass) 384 { 385 // generate member function type info 386 // it would be nicer if this could be in cv4_typidx, but the function info is not available there 387 uint nparam; 388 ubyte call = cv4_callconv(sfunc.Stype); 389 idx_t paramidx = cv4_arglist(sfunc.Stype,&nparam); 390 uint next = cv4_typidx(sfunc.Stype.Tnext); 391 392 type* classtype = cast(type*)fn.Fclass; 393 uint classidx = cv4_typidx(classtype); 394 type *tp = type_allocn(TYnptr, classtype); 395 uint thisidx = cv4_typidx(tp); // TODO 396 debtyp_t *d = debtyp_alloc(2 + 4 + 4 + 4 + 1 + 1 + 2 + 4 + 4); 397 TOWORD(d.data.ptr,LF_MFUNCTION_V2); 398 TOLONG(d.data.ptr + 2,next); // return type 399 TOLONG(d.data.ptr + 6,classidx); // class type 400 TOLONG(d.data.ptr + 10,thisidx); // this type 401 d.data.ptr[14] = call; 402 d.data.ptr[15] = 0; // reserved 403 TOWORD(d.data.ptr + 16,nparam); 404 TOLONG(d.data.ptr + 18,paramidx); 405 TOLONG(d.data.ptr + 22,0); // this adjust 406 typidx = cv_debtyp(d); 407 } 408 else 409 typidx = cv_typidx(sfunc.Stype); 410 411 version (MARS) 412 const(char)* id = sfunc.prettyIdent ? sfunc.prettyIdent : prettyident(sfunc); 413 else 414 const(char)* id = prettyident(sfunc); 415 size_t len = strlen(id); 416 if(len > CV8_MAX_SYMBOL_LENGTH) 417 len = CV8_MAX_SYMBOL_LENGTH; 418 /* 419 * 2 length (not including these 2 bytes) 420 * 2 S_GPROC_V3 421 * 4 parent 422 * 4 pend 423 * 4 pnext 424 * 4 size of function 425 * 4 size of function prolog 426 * 4 offset to function epilog 427 * 4 type index 428 * 6 seg:offset of function start 429 * 1 flags 430 * n 0 terminated name string 431 */ 432 Outbuffer *buf = currentfuncdata.f1buf; 433 buf.reserve(cast(uint)(2 + 2 + 4 * 7 + 6 + 1 + len + 1)); 434 buf.write16n(cast(int)(2 + 4 * 7 + 6 + 1 + len + 1)); 435 buf.write16n(sfunc.Sclass == SCstatic ? S_LPROC_V3 : S_GPROC_V3); 436 buf.write32(0); // parent 437 buf.write32(0); // pend 438 buf.write32(0); // pnext 439 buf.write32(cast(uint)currentfuncdata.section_length); // size of function 440 buf.write32(cast(uint)startoffset); // size of prolog 441 buf.write32(cast(uint)retoffset); // offset to epilog 442 buf.write32(typidx); 443 444 F1_Fixups f1f; 445 f1f.s = sfunc; 446 f1f.offset = cast(uint)buf.length(); 447 f1f.value = 0; 448 currentfuncdata.f1fixup.write(&f1f, f1f.sizeof); 449 buf.write32(0); 450 buf.write16n(0); 451 452 buf.writeByte(0); 453 buf.writen(id, len); 454 buf.writeByte(0); 455 456 struct cv8 457 { 458 nothrow: 459 // record for CV record S_BLOCK_V3 460 struct block_v3_data 461 { 462 ushort len; 463 ushort id; 464 uint pParent; 465 uint pEnd; 466 uint length; 467 uint offset; 468 ushort seg; 469 ubyte[1] name; 470 } 471 472 extern (C++) static void endArgs() 473 { 474 Outbuffer *buf = currentfuncdata.f1buf; 475 buf.write16(2); 476 buf.write16(S_ENDARG); 477 } 478 extern (C++) static void beginBlock(int offset, int length) 479 { 480 Outbuffer *buf = currentfuncdata.f1buf; 481 uint soffset = cast(uint)buf.length(); 482 // parent and end to be filled by linker 483 block_v3_data block32 = { block_v3_data.sizeof - 2, S_BLOCK_V3, 0, 0, length, offset, 0, [ 0 ] }; 484 buf.write(&block32, block32.sizeof); 485 size_t offOffset = cast(char*)&block32.offset - cast(char*)&block32; 486 487 F1_Fixups f1f; 488 f1f.s = currentfuncdata.sfunc; 489 f1f.offset = cast(uint)(soffset + offOffset); 490 f1f.value = offset; 491 currentfuncdata.f1fixup.write(&f1f, f1f.sizeof); 492 } 493 extern (C++) static void endBlock() 494 { 495 Outbuffer *buf = currentfuncdata.f1buf; 496 buf.write16(2); 497 buf.write16(S_END); 498 } 499 } 500 varStats_writeSymbolTable(globsym, &cv8_outsym, &cv8.endArgs, &cv8.beginBlock, &cv8.endBlock); 501 502 /* Put out function return record S_RETURN 503 * (VC doesn't, so we won't bother, either.) 504 */ 505 506 // Write function end symbol 507 buf.write16(2); 508 buf.write16(S_END); 509 510 currentfuncdata.f1buf = F1_buf; 511 currentfuncdata.f1fixup = F1fixup; 512 } 513 514 /********************************************** 515 */ 516 517 void cv8_linnum(Srcpos srcpos, uint offset) 518 { 519 version (MARS) 520 const sfilename = srcpos.Sfilename; 521 else 522 const sfilename = srcpos_name(srcpos); 523 //printf("cv8_linnum(file = %s, line = %d, offset = x%x)\n", sfilename, (int)srcpos.Slinnum, (uint)offset); 524 525 if (!sfilename) 526 return; 527 528 varStats_recordLineOffset(srcpos, offset); 529 530 __gshared uint lastoffset; 531 __gshared uint lastlinnum; 532 533 if (!currentfuncdata.srcfilename || 534 (currentfuncdata.srcfilename != sfilename && strcmp(currentfuncdata.srcfilename, sfilename))) 535 { 536 currentfuncdata.srcfilename = sfilename; 537 uint srcfileoff = cv8_addfile(sfilename); 538 539 // new file segment 540 currentfuncdata.linepairsegment = currentfuncdata.linepairstart + currentfuncdata.linepairbytes; 541 542 linepair.write32(srcfileoff); 543 linepair.write32(0); // reserve space for length information 544 linepair.write32(12); 545 currentfuncdata.linepairbytes += 12; 546 } 547 else if (offset <= lastoffset || srcpos.Slinnum == lastlinnum) 548 return; // avoid multiple entries for the same offset 549 550 lastoffset = offset; 551 lastlinnum = srcpos.Slinnum; 552 linepair.write32(offset); 553 linepair.write32(srcpos.Slinnum | 0x80000000); // mark as statement, not expression 554 555 currentfuncdata.linepairbytes += 8; 556 557 // update segment length 558 auto segmentbytes = currentfuncdata.linepairstart + currentfuncdata.linepairbytes - currentfuncdata.linepairsegment; 559 auto segmentheader = cast(uint*)(linepair.buf + currentfuncdata.linepairsegment); 560 segmentheader[1] = (segmentbytes - 12) / 8; 561 segmentheader[2] = segmentbytes; 562 } 563 564 /********************************************** 565 * Add source file, if it isn't already there. 566 * Return offset into F4. 567 */ 568 569 uint cv8_addfile(const(char)* filename) 570 { 571 //printf("cv8_addfile('%s')\n", filename); 572 573 /* The algorithms here use a linear search. This is acceptable only 574 * because we expect only 1 or 2 files to appear. 575 * Unlike C, there won't be lots of .h source files to be accounted for. 576 */ 577 578 uint length = cast(uint)F3_buf.length(); 579 ubyte *p = F3_buf.buf; 580 size_t len = strlen(filename); 581 582 // ensure the filename is absolute to help the debugger to find the source 583 // without having to know the working directory during compilation 584 __gshared char[260] cwd = 0; 585 __gshared uint cwdlen; 586 bool abs = (*filename == '\\') || 587 (*filename == '/') || 588 (*filename && filename[1] == ':'); 589 590 if (!abs && cwd[0] == 0) 591 { 592 if (getcwd(cwd.ptr, cwd.sizeof)) 593 { 594 cwdlen = cast(uint)strlen(cwd.ptr); 595 if(cwd[cwdlen - 1] != '\\' && cwd[cwdlen - 1] != '/') 596 cwd[cwdlen++] = '\\'; 597 } 598 } 599 uint off = 1; 600 while (off + len < length) 601 { 602 if (!abs) 603 { 604 if (memcmp(p + off, cwd.ptr, cwdlen) == 0 && 605 memcmp(p + off + cwdlen, filename, len + 1) == 0) 606 goto L1; 607 } 608 else if (memcmp(p + off, filename, len + 1) == 0) 609 { // Already there 610 //printf("\talready there at %x\n", off); 611 goto L1; 612 } 613 off += strlen(cast(const(char)* )(p + off)) + 1; 614 } 615 off = length; 616 // Add it 617 if(!abs) 618 F3_buf.write(cwd.ptr, cwdlen); 619 F3_buf.write(filename, cast(uint)(len + 1)); 620 621 L1: 622 // off is the offset of the filename in F3. 623 // Find it in F4. 624 625 length = cast(uint)F4_buf.length(); 626 p = F4_buf.buf; 627 628 uint u = 0; 629 while (u + 8 <= length) 630 { 631 //printf("\t%x\n", *(uint *)(p + u)); 632 if (off == *cast(uint *)(p + u)) 633 { 634 //printf("\tfound %x\n", u); 635 return u; 636 } 637 u += 4; 638 ushort type = *cast(ushort *)(p + u); 639 u += 2; 640 if (type == 0x0110) 641 u += 16; // MD5 checksum 642 u += 2; 643 } 644 645 // Not there. Add it. 646 F4_buf.write32(off); 647 648 /* Write 10 01 [MD5 checksum] 649 * or 650 * 00 00 651 */ 652 F4_buf.write16(0); 653 654 // 2 bytes of pad 655 F4_buf.write16(0); 656 657 //printf("\tadded %x\n", length); 658 return length; 659 } 660 661 void cv8_writesection(int seg, uint type, Outbuffer *buf) 662 { 663 /* Write out as: 664 * bytes desc 665 * -------+---- 666 * 4 type 667 * 4 length 668 * length data 669 * pad pad to 4 byte boundary 670 */ 671 uint off = cast(uint)SegData[seg].SDoffset; 672 objmod.bytes(seg,off,4,&type); 673 uint length = cast(uint)buf.length(); 674 objmod.bytes(seg,off+4,4,&length); 675 objmod.bytes(seg,off+8,length,buf.buf); 676 // Align to 4 677 uint pad = ((length + 3) & ~3) - length; 678 objmod.lidata(seg,off+8+length,pad); 679 } 680 681 void cv8_outsym(Symbol *s) 682 { 683 //printf("cv8_outsym(s = '%s')\n", s.Sident); 684 //type_print(s.Stype); 685 //symbol_print(s); 686 if (s.Sflags & SFLnodebug) 687 return; 688 689 idx_t typidx = cv_typidx(s.Stype); 690 //printf("typidx = %x\n", typidx); 691 version (MARS) 692 const(char)* id = s.prettyIdent ? s.prettyIdent : prettyident(s); 693 else 694 const(char)* id = prettyident(s); 695 size_t len = strlen(id); 696 697 if(len > CV8_MAX_SYMBOL_LENGTH) 698 len = CV8_MAX_SYMBOL_LENGTH; 699 700 F1_Fixups f1f; 701 f1f.value = 0; 702 Outbuffer *buf = currentfuncdata.f1buf; 703 704 uint sr; 705 uint base; 706 switch (s.Sclass) 707 { 708 case SCparameter: 709 case SCregpar: 710 case SCshadowreg: 711 if (s.Sfl == FLreg) 712 { 713 s.Sfl = FLpara; 714 cv8_outsym(s); 715 s.Sfl = FLreg; 716 goto case_register; 717 } 718 base = cast(uint)(Para.size - BPoff); // cancel out add of BPoff 719 goto L1; 720 721 case SCauto: 722 if (s.Sfl == FLreg) 723 goto case_register; 724 case_auto: 725 base = cast(uint)Auto.size; 726 L1: 727 if (s.Sscope) // local variables moved into the closure cannot be emitted directly 728 break; 729 static if (1) 730 { 731 // Register relative addressing 732 buf.reserve(cast(uint)(2 + 2 + 4 + 4 + 2 + len + 1)); 733 buf.write16n(cast(uint)(2 + 4 + 4 + 2 + len + 1)); 734 buf.write16n(0x1111); 735 buf.write32(cast(uint)(s.Soffset + base + BPoff)); 736 buf.write32(typidx); 737 buf.write16n(I64 ? 334 : 22); // relative to RBP/EBP 738 cv8_writename(buf, id, len); 739 buf.writeByte(0); 740 } 741 else 742 { 743 // This is supposed to work, implicit BP relative addressing, but it does not 744 buf.reserve(2 + 2 + 4 + 4 + len + 1); 745 buf.write16n( 2 + 4 + 4 + len + 1); 746 buf.write16n(S_BPREL_V3); 747 buf.write32(s.Soffset + base + BPoff); 748 buf.write32(typidx); 749 cv8_writename(buf, id, len); 750 buf.writeByte(0); 751 } 752 break; 753 754 case SCbprel: 755 base = -BPoff; 756 goto L1; 757 758 case SCfastpar: 759 if (s.Sfl != FLreg) 760 { base = cast(uint)Fast.size; 761 goto L1; 762 } 763 goto L2; 764 765 case SCregister: 766 if (s.Sfl != FLreg) 767 goto case_auto; 768 goto case; 769 770 case SCpseudo: 771 case_register: 772 L2: 773 buf.reserve(cast(uint)(2 + 2 + 4 + 2 + len + 1)); 774 buf.write16n(cast(uint)(2 + 4 + 2 + len + 1)); 775 buf.write16n(S_REGISTER_V3); 776 buf.write32(typidx); 777 buf.write16n(cv8_regnum(s)); 778 cv8_writename(buf, id, len); 779 buf.writeByte(0); 780 break; 781 782 case SCextern: 783 break; 784 785 case SCstatic: 786 case SClocstat: 787 sr = S_LDATA_V3; 788 goto Ldata; 789 790 case SCglobal: 791 case SCcomdat: 792 case SCcomdef: 793 sr = S_GDATA_V3; 794 Ldata: 795 /* 796 * 2 length (not including these 2 bytes) 797 * 2 S_GDATA_V2 798 * 4 typidx 799 * 6 ref to symbol 800 * n 0 terminated name string 801 */ 802 if (s.ty() & mTYthread) // thread local storage 803 sr = (sr == S_GDATA_V3) ? 0x1113 : 0x1112; 804 805 buf.reserve(cast(uint)(2 + 2 + 4 + 6 + len + 1)); 806 buf.write16n(cast(uint)(2 + 4 + 6 + len + 1)); 807 buf.write16n(sr); 808 buf.write32(typidx); 809 810 f1f.s = s; 811 f1f.offset = cast(uint)buf.length(); 812 F1fixup.write(&f1f, f1f.sizeof); 813 buf.write32(0); 814 buf.write16n(0); 815 816 cv8_writename(buf, id, len); 817 buf.writeByte(0); 818 break; 819 820 default: 821 break; 822 } 823 } 824 825 826 /******************************************* 827 * Put out a name for a user defined type. 828 * Input: 829 * id the name 830 * typidx and its type 831 */ 832 void cv8_udt(const(char)* id, idx_t typidx) 833 { 834 //printf("cv8_udt('%s', %x)\n", id, typidx); 835 Outbuffer *buf = currentfuncdata.f1buf; 836 size_t len = strlen(id); 837 838 if (len > CV8_MAX_SYMBOL_LENGTH) 839 len = CV8_MAX_SYMBOL_LENGTH; 840 buf.reserve(cast(uint)(2 + 2 + 4 + len + 1)); 841 buf.write16n(cast(uint)(2 + 4 + len + 1)); 842 buf.write16n(S_UDT_V3); 843 buf.write32(typidx); 844 cv8_writename(buf, id, len); 845 buf.writeByte(0); 846 } 847 848 /********************************************* 849 * Get Codeview register number for symbol s. 850 */ 851 int cv8_regnum(Symbol *s) 852 { 853 int reg = s.Sreglsw; 854 assert(s.Sfl == FLreg); 855 if ((1 << reg) & XMMREGS) 856 return reg - XMM0 + 154; 857 switch (type_size(s.Stype)) 858 { 859 case 1: 860 if (reg < 4) 861 reg += 1; 862 else if (reg >= 4 && reg < 8) 863 reg += 324 - 4; 864 else 865 reg += 344 - 4; 866 break; 867 868 case 2: 869 if (reg < 8) 870 reg += 9; 871 else 872 reg += 352 - 8; 873 break; 874 875 case 4: 876 if (reg < 8) 877 reg += 17; 878 else 879 reg += 360 - 8; 880 break; 881 882 case 8: 883 reg += 328; 884 break; 885 886 default: 887 reg = 0; 888 break; 889 } 890 return reg; 891 } 892 893 /*************************************** 894 * Put out a forward ref for structs, unions, and classes. 895 * Only put out the real definitions with toDebug(). 896 */ 897 idx_t cv8_fwdref(Symbol *s) 898 { 899 assert(config.fulltypes == CV8); 900 // if (s.Stypidx && !global.params.multiobj) 901 // return s.Stypidx; 902 struct_t *st = s.Sstruct; 903 uint leaf; 904 uint numidx; 905 if (st.Sflags & STRunion) 906 { 907 leaf = LF_UNION_V3; 908 numidx = 10; 909 } 910 else if (st.Sflags & STRclass) 911 { 912 leaf = LF_CLASS_V3; 913 numidx = 18; 914 } 915 else 916 { 917 leaf = LF_STRUCTURE_V3; 918 numidx = 18; 919 } 920 uint len = numidx + cv4_numericbytes(0); 921 int idlen = cast(int)strlen(s.Sident.ptr); 922 923 if (idlen > CV8_MAX_SYMBOL_LENGTH) 924 idlen = CV8_MAX_SYMBOL_LENGTH; 925 926 debtyp_t *d = debtyp_alloc(len + idlen + 1); 927 TOWORD(d.data.ptr, leaf); 928 TOWORD(d.data.ptr + 2, 0); // number of fields 929 TOWORD(d.data.ptr + 4, 0x80); // property 930 TOLONG(d.data.ptr + 6, 0); // field list 931 if (leaf == LF_CLASS_V3 || leaf == LF_STRUCTURE_V3) 932 { 933 TOLONG(d.data.ptr + 10, 0); // dList 934 TOLONG(d.data.ptr + 14, 0); // vshape 935 } 936 cv4_storenumeric(d.data.ptr + numidx, 0); 937 cv_namestring(d.data.ptr + len, s.Sident.ptr, idlen); 938 d.data.ptr[len + idlen] = 0; 939 idx_t typidx = cv_debtyp(d); 940 s.Stypidx = typidx; 941 942 return typidx; 943 } 944 945 /**************************************** 946 * Return type index for a darray of type E[] 947 * Input: 948 * t darray type 949 * etypidx type index for E 950 */ 951 idx_t cv8_darray(type *t, idx_t etypidx) 952 { 953 //printf("cv8_darray(etypidx = %x)\n", etypidx); 954 /* Put out a struct: 955 * struct dArray { 956 * size_t length; 957 * E* ptr; 958 * } 959 */ 960 961 static if (0) 962 { 963 d = debtyp_alloc(18); 964 TOWORD(d.data.ptr, 0x100F); 965 TOWORD(d.data.ptr + 2, OEM); 966 TOWORD(d.data.ptr + 4, 1); // 1 = dynamic array 967 TOLONG(d.data.ptr + 6, 2); // count of type indices to follow 968 TOLONG(d.data.ptr + 10, 0x23); // index type, T_UQUAD 969 TOLONG(d.data.ptr + 14, next); // element type 970 return cv_debtyp(d); 971 } 972 973 type *tp = type_pointer(t.Tnext); 974 idx_t ptridx = cv4_typidx(tp); 975 type_free(tp); 976 977 __gshared const ubyte[38] fl = 978 [ 979 0x03, 0x12, // LF_FIELDLIST_V2 980 0x0d, 0x15, // LF_MEMBER_V3 981 0x03, 0x00, // attribute 982 0x23, 0x00, 0x00, 0x00, // size_t 983 0x00, 0x00, // offset 984 'l', 'e', 'n', 'g', 't', 'h', 0x00, 985 0xf3, 0xf2, 0xf1, // align to 4-byte including length word before data 986 0x0d, 0x15, 987 0x03, 0x00, 988 0x00, 0x00, 0x00, 0x00, // etypidx 989 0x08, 0x00, 990 'p', 't', 'r', 0x00, 991 0xf2, 0xf1, 992 ]; 993 994 debtyp_t *f = debtyp_alloc(fl.sizeof); 995 memcpy(f.data.ptr,fl.ptr,fl.sizeof); 996 TOLONG(f.data.ptr + 6, I64 ? 0x23 : 0x22); // size_t 997 TOLONG(f.data.ptr + 26, ptridx); 998 TOWORD(f.data.ptr + 30, _tysize[TYnptr]); 999 idx_t fieldlist = cv_debtyp(f); 1000 1001 const(char)* id; 1002 switch (t.Tnext.Tty) 1003 { 1004 case mTYimmutable | TYchar: 1005 id = "string"; 1006 break; 1007 1008 case mTYimmutable | TYwchar_t: 1009 id = "wstring"; 1010 break; 1011 1012 case mTYimmutable | TYdchar: 1013 id = "dstring"; 1014 break; 1015 1016 default: 1017 id = t.Tident ? t.Tident : "dArray"; 1018 break; 1019 } 1020 1021 int idlen = cast(int)strlen(id); 1022 1023 if (idlen > CV8_MAX_SYMBOL_LENGTH) 1024 idlen = CV8_MAX_SYMBOL_LENGTH; 1025 1026 debtyp_t *d = debtyp_alloc(20 + idlen + 1); 1027 TOWORD(d.data.ptr, LF_STRUCTURE_V3); 1028 TOWORD(d.data.ptr + 2, 2); // count 1029 TOWORD(d.data.ptr + 4, 0); // property 1030 TOLONG(d.data.ptr + 6, fieldlist); 1031 TOLONG(d.data.ptr + 10, 0); // dList 1032 TOLONG(d.data.ptr + 14, 0); // vtshape 1033 TOWORD(d.data.ptr + 18, 2 * _tysize[TYnptr]); // size 1034 cv_namestring(d.data.ptr + 20, id, idlen); 1035 d.data.ptr[20 + idlen] = 0; 1036 1037 idx_t top = cv_numdebtypes(); 1038 idx_t debidx = cv_debtyp(d); 1039 if(top != cv_numdebtypes()) 1040 cv8_udt(id, debidx); 1041 1042 return debidx; 1043 } 1044 1045 /**************************************** 1046 * Return type index for a delegate 1047 * Input: 1048 * t delegate type 1049 * functypidx type index for pointer to function 1050 */ 1051 idx_t cv8_ddelegate(type *t, idx_t functypidx) 1052 { 1053 //printf("cv8_ddelegate(functypidx = %x)\n", functypidx); 1054 /* Put out a struct: 1055 * struct dDelegate { 1056 * void* ptr; 1057 * function* funcptr; 1058 * } 1059 */ 1060 1061 type *tv = type_fake(TYnptr); 1062 tv.Tcount++; 1063 idx_t pvidx = cv4_typidx(tv); 1064 type_free(tv); 1065 1066 type *tp = type_pointer(t.Tnext); 1067 idx_t ptridx = cv4_typidx(tp); 1068 type_free(tp); 1069 1070 static if (0) 1071 { 1072 debtyp_t *d = debtyp_alloc(18); 1073 TOWORD(d.data.ptr, 0x100F); 1074 TOWORD(d.data.ptr + 2, OEM); 1075 TOWORD(d.data.ptr + 4, 3); // 3 = delegate 1076 TOLONG(d.data.ptr + 6, 2); // count of type indices to follow 1077 TOLONG(d.data.ptr + 10, key); // void* type 1078 TOLONG(d.data.ptr + 14, functypidx); // function type 1079 } 1080 else 1081 { 1082 __gshared const ubyte[38] fl = 1083 [ 1084 0x03, 0x12, // LF_FIELDLIST_V2 1085 0x0d, 0x15, // LF_MEMBER_V3 1086 0x03, 0x00, // attribute 1087 0x00, 0x00, 0x00, 0x00, // void* 1088 0x00, 0x00, // offset 1089 'p','t','r',0, // "ptr" 1090 0xf2, 0xf1, // align to 4-byte including length word before data 1091 0x0d, 0x15, 1092 0x03, 0x00, 1093 0x00, 0x00, 0x00, 0x00, // ptrtypidx 1094 0x08, 0x00, 1095 'f', 'u','n','c','p','t','r', 0, // "funcptr" 1096 0xf2, 0xf1, 1097 ]; 1098 1099 debtyp_t *f = debtyp_alloc(fl.sizeof); 1100 memcpy(f.data.ptr,fl.ptr,fl.sizeof); 1101 TOLONG(f.data.ptr + 6, pvidx); 1102 TOLONG(f.data.ptr + 22, ptridx); 1103 TOWORD(f.data.ptr + 26, _tysize[TYnptr]); 1104 idx_t fieldlist = cv_debtyp(f); 1105 1106 const(char)* id = "dDelegate"; 1107 int idlen = cast(int)strlen(id); 1108 if (idlen > CV8_MAX_SYMBOL_LENGTH) 1109 idlen = CV8_MAX_SYMBOL_LENGTH; 1110 1111 debtyp_t *d = debtyp_alloc(20 + idlen + 1); 1112 TOWORD(d.data.ptr, LF_STRUCTURE_V3); 1113 TOWORD(d.data.ptr + 2, 2); // count 1114 TOWORD(d.data.ptr + 4, 0); // property 1115 TOLONG(d.data.ptr + 6, fieldlist); 1116 TOLONG(d.data.ptr + 10, 0); // dList 1117 TOLONG(d.data.ptr + 14, 0); // vtshape 1118 TOWORD(d.data.ptr + 18, 2 * _tysize[TYnptr]); // size 1119 memcpy(d.data.ptr + 20, id, idlen); 1120 d.data.ptr[20 + idlen] = 0; 1121 } 1122 return cv_debtyp(d); 1123 } 1124 1125 /**************************************** 1126 * Return type index for a aarray of type Value[Key] 1127 * Input: 1128 * t associative array type 1129 * keyidx key type 1130 * validx value type 1131 */ 1132 idx_t cv8_daarray(type *t, idx_t keyidx, idx_t validx) 1133 { 1134 //printf("cv8_daarray(keyidx = %x, validx = %x)\n", keyidx, validx); 1135 /* Put out a struct: 1136 * struct dAssocArray { 1137 * void* ptr; 1138 * typedef key-type __key_t; 1139 * typedef val-type __val_t; 1140 * } 1141 */ 1142 1143 static if (0) 1144 { 1145 debtyp_t *d = debtyp_alloc(18); 1146 TOWORD(d.data.ptr, 0x100F); 1147 TOWORD(d.data.ptr + 2, OEM); 1148 TOWORD(d.data.ptr + 4, 2); // 2 = associative array 1149 TOLONG(d.data.ptr + 6, 2); // count of type indices to follow 1150 TOLONG(d.data.ptr + 10, keyidx); // key type 1151 TOLONG(d.data.ptr + 14, validx); // element type 1152 } 1153 else 1154 { 1155 type *tv = type_fake(TYnptr); 1156 tv.Tcount++; 1157 idx_t pvidx = cv4_typidx(tv); 1158 type_free(tv); 1159 1160 __gshared const ubyte[50] fl = 1161 [ 1162 0x03, 0x12, // LF_FIELDLIST_V2 1163 0x0d, 0x15, // LF_MEMBER_V3 1164 0x03, 0x00, // attribute 1165 0x00, 0x00, 0x00, 0x00, // void* 1166 0x00, 0x00, // offset 1167 'p','t','r',0, // "ptr" 1168 0xf2, 0xf1, // align to 4-byte including field id 1169 // offset 18 1170 0x10, 0x15, // LF_NESTTYPE_V3 1171 0x00, 0x00, // padding 1172 0x00, 0x00, 0x00, 0x00, // key type 1173 '_','_','k','e','y','_','t',0, // "__key_t" 1174 // offset 34 1175 0x10, 0x15, // LF_NESTTYPE_V3 1176 0x00, 0x00, // padding 1177 0x00, 0x00, 0x00, 0x00, // value type 1178 '_','_','v','a','l','_','t',0, // "__val_t" 1179 ]; 1180 1181 debtyp_t *f = debtyp_alloc(fl.sizeof); 1182 memcpy(f.data.ptr,fl.ptr,fl.sizeof); 1183 TOLONG(f.data.ptr + 6, pvidx); 1184 TOLONG(f.data.ptr + 22, keyidx); 1185 TOLONG(f.data.ptr + 38, validx); 1186 idx_t fieldlist = cv_debtyp(f); 1187 1188 const(char)* id = t.Tident ? t.Tident : "dAssocArray"; 1189 int idlen = cast(int)strlen(id); 1190 if (idlen > CV8_MAX_SYMBOL_LENGTH) 1191 idlen = CV8_MAX_SYMBOL_LENGTH; 1192 1193 debtyp_t *d = debtyp_alloc(20 + idlen + 1); 1194 TOWORD(d.data.ptr, LF_STRUCTURE_V3); 1195 TOWORD(d.data.ptr + 2, 1); // count 1196 TOWORD(d.data.ptr + 4, 0); // property 1197 TOLONG(d.data.ptr + 6, fieldlist); 1198 TOLONG(d.data.ptr + 10, 0); // dList 1199 TOLONG(d.data.ptr + 14, 0); // vtshape 1200 TOWORD(d.data.ptr + 18, _tysize[TYnptr]); // size 1201 memcpy(d.data.ptr + 20, id, idlen); 1202 d.data.ptr[20 + idlen] = 0; 1203 1204 } 1205 return cv_debtyp(d); 1206 } 1207 1208 } 1209 1210 }