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