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