1 /** 2 * Generate debug info in the CV4 debug format. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/tocsym.d, _tocvdebug.d) 8 * Documentation: https://dlang.org/phobos/dmd_tocvdebug.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/tocvdebug.d 10 */ 11 12 module dmd.tocvdebug; 13 14 import core.stdc.stdio; 15 import core.stdc.string; 16 import core.stdc.stddef; 17 import core.stdc.stdlib; 18 import core.stdc.time; 19 20 import dmd.root.array; 21 import dmd.root.rmem; 22 23 import dmd.aggregate; 24 import dmd.astenums; 25 import dmd.dclass; 26 import dmd.declaration; 27 import dmd.denum; 28 import dmd.dmodule; 29 import dmd.dsymbol; 30 import dmd.dstruct; 31 import dmd.dtemplate; 32 import dmd.func; 33 import dmd.globals; 34 import dmd.id; 35 import dmd.mtype; 36 import dmd.target; 37 import dmd.toctype; 38 import dmd.visitor; 39 40 import dmd.backend.cc; 41 import dmd.backend.cdef; 42 import dmd.backend.cgcv; 43 import dmd.backend.code; 44 import dmd.backend.cv4; 45 import dmd.backend.dlist; 46 import dmd.backend.dt; 47 import dmd.backend.global; 48 import dmd.backend.obj; 49 import dmd.backend.oper; 50 import dmd.backend.ty; 51 import dmd.backend.type; 52 53 /* The CV4 debug format is defined in: 54 * "CV4 Symbolic Debug Information Specification" 55 * rev 3.1 March 5, 1993 56 * Languages Business Unit 57 * Microsoft 58 */ 59 60 /****************************** 61 * CV4 pg. 25 62 * Convert D visibility attribute to cv attribute. 63 */ 64 65 uint visibilityToCVAttr(Visibility.Kind vis) pure nothrow @safe @nogc 66 { 67 uint attribute; 68 69 final switch (vis) 70 { 71 case Visibility.Kind.private_: attribute = 1; break; 72 case Visibility.Kind.package_: attribute = 2; break; 73 case Visibility.Kind.protected_: attribute = 2; break; 74 case Visibility.Kind.public_: attribute = 3; break; 75 case Visibility.Kind.export_: attribute = 3; break; 76 77 case Visibility.Kind.undefined: 78 case Visibility.Kind.none: 79 //printf("vis = %d\n", vis); 80 assert(0); 81 } 82 return attribute; 83 } 84 85 uint cv4_memfunctypidx(FuncDeclaration fd) 86 { 87 //printf("cv4_memfunctypidx(fd = '%s')\n", fd.toChars()); 88 89 type *t = Type_toCtype(fd.type); 90 AggregateDeclaration ad = fd.isMemberLocal(); 91 if (!ad) 92 return cv4_typidx(t); 93 94 // It's a member function, which gets a special type record 95 96 const idx_t thisidx = fd.isStatic() 97 ? dttab4[TYvoid] 98 : (ad.handleType() ? cv4_typidx(Type_toCtype(ad.handleType())) : 0); 99 assert(thisidx); 100 101 uint nparam; 102 const idx_t paramidx = cv4_arglist(t,&nparam); 103 104 const ubyte call = cv4_callconv(t); 105 106 switch (config.fulltypes) 107 { 108 case CV4: 109 { 110 debtyp_t* d = debtyp_alloc(18); 111 ubyte *p = &d.data[0]; 112 TOWORD(p,LF_MFUNCTION); 113 TOWORD(p + 2,cv4_typidx(t.Tnext)); 114 TOWORD(p + 4,cv4_typidx(Type_toCtype(ad.type))); 115 TOWORD(p + 6,thisidx); 116 p[8] = call; 117 p[9] = 0; // reserved 118 TOWORD(p + 10,nparam); 119 TOWORD(p + 12,paramidx); 120 TOLONG(p + 14,0); // thisadjust 121 return cv_debtyp(d); 122 } 123 case CV8: 124 { 125 debtyp_t* d = debtyp_alloc(26); 126 ubyte *p = &d.data[0]; 127 TOWORD(p,0x1009); 128 TOLONG(p + 2,cv4_typidx(t.Tnext)); 129 TOLONG(p + 6,cv4_typidx(Type_toCtype(ad.type))); 130 TOLONG(p + 10,thisidx); 131 p[14] = call; 132 p[15] = 0; // reserved 133 TOWORD(p + 16,nparam); 134 TOLONG(p + 18,paramidx); 135 TOLONG(p + 22,0); // thisadjust 136 return cv_debtyp(d); 137 } 138 default: 139 assert(0); 140 } 141 } 142 143 enum CV4_NAMELENMAX = 0x3b9f; // found by trial and error 144 enum CV8_NAMELENMAX = 0xffff; // length record is 16-bit only 145 146 uint cv4_Denum(EnumDeclaration e) 147 { 148 //dbg_printf("cv4_Denum(%s)\n", e.toChars()); 149 const uint property = (!e.members || !e.memtype || !e.memtype.isintegral()) 150 ? 0x80 // enum is forward referenced or non-integer 151 : 0; 152 153 // Compute the number of fields, and the length of the fieldlist record 154 CvFieldList mc = CvFieldList(0, 0); 155 if (!property) 156 { 157 for (size_t i = 0; i < e.members.length; i++) 158 { 159 EnumMember sf = (*e.members)[i].isEnumMember(); 160 if (!sf) 161 continue; 162 const value = sf.value().toInteger(); 163 164 // store only member's simple name 165 uint len = 4 + cv4_numericbytes(cast(uint)value) + cv_stringbytes(sf.toChars()); 166 167 len = cv_align(null, len); 168 mc.count(len); 169 170 } 171 } 172 173 const id = e.toPrettyChars(); 174 uint len; 175 debtyp_t *d; 176 const uint memtype = e.memtype ? cv4_typidx(Type_toCtype(e.memtype)) : 0; 177 switch (config.fulltypes) 178 { 179 case CV8: 180 len = 14; 181 d = debtyp_alloc(len + cv_stringbytes(id)); 182 TOWORD(d.data.ptr,LF_ENUM_V3); 183 TOLONG(d.data.ptr + 6,memtype); 184 TOWORD(d.data.ptr + 4,property); 185 len += cv_namestring(d.data.ptr + len,id); 186 break; 187 188 case CV4: 189 len = 10; 190 d = debtyp_alloc(len + cv_stringbytes(id)); 191 TOWORD(d.data.ptr,LF_ENUM); 192 TOWORD(d.data.ptr + 4,memtype); 193 TOWORD(d.data.ptr + 8,property); 194 len += cv_namestring(d.data.ptr + len,id); 195 break; 196 197 default: 198 assert(0); 199 } 200 const length_save = d.length; 201 d.length = 0; // so cv_debtyp() will allocate new 202 const idx_t typidx = cv_debtyp(d); 203 d.length = length_save; // restore length 204 205 TOWORD(d.data.ptr + 2, mc.nfields); 206 207 uint fieldlist = 0; 208 if (!property) // if forward reference, then fieldlist is 0 209 { 210 // Generate fieldlist type record 211 mc.alloc(); 212 213 // And fill it in 214 for (size_t i = 0; i < e.members.length; i++) 215 { 216 EnumMember sf = (*e.members)[i].isEnumMember(); 217 if (!sf) 218 continue; 219 220 ubyte* p = mc.writePtr(); 221 dinteger_t value = sf.value().toInteger(); 222 TOWORD(p, (config.fulltypes == CV8) ? LF_ENUMERATE_V3 : LF_ENUMERATE); 223 uint attribute = 0; 224 TOWORD(p + 2, attribute); 225 cv4_storenumeric(p + 4,cast(uint)value); 226 uint j = 4 + cv4_numericbytes(cast(uint)value); 227 // store only member's simple name 228 j += cv_namestring(p + j, sf.toChars()); 229 j = cv_align(p + j, j); 230 mc.written(j); 231 // If enum is not a member of a class, output enum members as constants 232 // if (!isclassmember(s)) 233 // { 234 // cv4_outsym(sf); 235 // } 236 } 237 fieldlist = mc.debtyp(); 238 } 239 240 if (config.fulltypes == CV8) 241 TOLONG(d.data.ptr + 10,fieldlist); 242 else 243 TOWORD(d.data.ptr + 6,fieldlist); 244 245 // cv4_outsym(s); 246 return typidx; 247 } 248 249 /************************************* 250 * Align and pad. 251 * Returns: 252 * aligned count 253 */ 254 uint cv_align(ubyte *p, uint n) 255 { 256 if (config.fulltypes == CV8) 257 { 258 if (p) 259 { 260 uint npad = -n & 3; 261 while (npad) 262 { 263 *p = cast(ubyte)(0xF0 + npad); 264 ++p; 265 --npad; 266 } 267 } 268 n = (n + 3) & ~3; 269 } 270 return n; 271 } 272 273 /************************************* 274 * write a UDT record to the object file 275 * Params: 276 * id = name of user defined type 277 * typidx = type index 278 */ 279 void cv_udt(const char* id, uint typidx) 280 { 281 if (config.fulltypes == CV8) 282 return cv8_udt(id, typidx); 283 284 const len = strlen(id); 285 ubyte *debsym = cast(ubyte *) alloca(39 + IDOHD + len); 286 287 // Output a 'user-defined type' for the tag name 288 TOWORD(debsym + 2,S_UDT); 289 TOIDX(debsym + 4,typidx); 290 uint length = 2 + 2 + cgcv.sz_idx; 291 length += cv_namestring(debsym + length,id); 292 TOWORD(debsym,length - 2); 293 294 assert(length <= 40 + len); 295 objmod.write_bytes(SegData[DEBSYM],debsym[0 .. length]); 296 } 297 298 /* ==================================================================== */ 299 300 /**************************** 301 * Emit symbolic debug info in CV format. 302 */ 303 304 void toDebug(EnumDeclaration ed) 305 { 306 if (target.os != Target.OS.Windows) 307 return; 308 309 //printf("EnumDeclaration::toDebug('%s')\n", ed.toChars()); 310 311 assert(config.fulltypes >= CV4); 312 313 // If it is a member, it is handled by cvMember() 314 if (!ed.isMember()) 315 { 316 const id = ed.toPrettyChars(true); 317 const idx_t typidx = cv4_Denum(ed); 318 cv_udt(id, typidx); 319 } 320 } 321 322 /**************************** 323 * Helper struct for field list records LF_FIELDLIST/LF_FIELDLIST_V2 324 * 325 * if the size exceeds the maximum length of a record, the last entry 326 * is an LF_INDEX entry with the type index pointing to the next field list record 327 * 328 * Processing is done in two phases: 329 * 330 * Phase 1: computing the size of the field list and distributing it over multiple records 331 * - construct CvFieldList with some precalculated field count/length 332 * - for each field, call count(length of field) 333 * 334 * Phase 2: write the actual data 335 * - call alloc() to allocate debtyp's 336 * - for each field, 337 * - call writePtr() to get a pointer into the current debtyp 338 * - fill memory with field data 339 * - call written(length of field) 340 * - call debtyp() to create type records and return the index of the first one 341 */ 342 struct CvFieldList 343 { 344 // one LF_FIELDLIST record 345 static struct FLChunk 346 { 347 uint length; // accumulated during "count" phase 348 349 debtyp_t *dt; 350 uint writepos; // write position in dt 351 } 352 353 uint nfields; 354 uint writeIndex; 355 Array!FLChunk fieldLists; 356 357 const uint fieldLenMax; 358 const uint fieldIndexLen; 359 360 const bool canSplitList; 361 362 this(uint fields, uint len) scope 363 { 364 canSplitList = config.fulltypes == CV8; // optlink bails out with LF_INDEX 365 fieldIndexLen = canSplitList ? (config.fulltypes == CV8 ? 2 + 2 + 4 : 2 + 2) : 0; 366 fieldLenMax = (config.fulltypes == CV8 ? CV8_NAMELENMAX : CV4_NAMELENMAX) - fieldIndexLen; 367 368 assert(len < fieldLenMax); 369 nfields = fields; 370 fieldLists.push(FLChunk(2 + len)); 371 } 372 373 void count(uint n) 374 { 375 if (n) 376 { 377 nfields++; 378 assert(n < fieldLenMax); 379 if (fieldLists[$-1].length + n > fieldLenMax) 380 fieldLists.push(FLChunk(2 + n)); 381 else 382 fieldLists[$-1].length += n; 383 } 384 } 385 386 void alloc() 387 { 388 foreach (i, ref fld; fieldLists) 389 { 390 fld.dt = debtyp_alloc(fld.length + (i < fieldLists.length - 1 ? fieldIndexLen : 0)); 391 TOWORD(fld.dt.data.ptr, config.fulltypes == CV8 ? LF_FIELDLIST_V2 : LF_FIELDLIST); 392 fld.writepos = 2; 393 } 394 } 395 396 ubyte* writePtr() 397 { 398 assert(writeIndex < fieldLists.length); 399 auto fld = &fieldLists[writeIndex]; 400 if (fld.writepos >= fld.length) 401 { 402 assert(fld.writepos == fld.length); 403 if (writeIndex < fieldLists.length - 1) // if false, all further attempts must not actually write any data 404 { 405 writeIndex++; 406 fld++; 407 } 408 } 409 return fld.dt.data.ptr + fld.writepos; 410 } 411 412 void written(uint n) 413 { 414 assert(fieldLists[writeIndex].writepos + n <= fieldLists[writeIndex].length); 415 fieldLists[writeIndex].writepos += n; 416 } 417 418 idx_t debtyp() 419 { 420 idx_t typidx; 421 auto numCreate = canSplitList ? fieldLists.length : 1; 422 for(auto i = numCreate; i > 0; --i) 423 { 424 auto fld = &fieldLists[i - 1]; 425 if (typidx) 426 { 427 ubyte* p = fld.dt.data.ptr + fld.writepos; 428 if (config.fulltypes == CV8) 429 { 430 TOWORD (p, LF_INDEX_V2); 431 TOWORD (p + 2, 0); // padding 432 TOLONG (p + 4, typidx); 433 } 434 else 435 { 436 TOWORD (p, LF_INDEX); 437 TOWORD (p + 2, typidx); 438 } 439 } 440 typidx = cv_debtyp(fld.dt); 441 } 442 return typidx; 443 } 444 } 445 446 // Lambda function 447 int cv_mem_count(Dsymbol s, void* ctx) 448 { 449 auto pmc = cast(CvFieldList *) ctx; 450 int nwritten = cvMember(s, null); 451 pmc.count(nwritten); 452 return 0; 453 } 454 455 // Lambda function 456 int cv_mem_p(Dsymbol s, void* ctx) 457 { 458 auto pmc = cast(CvFieldList *) ctx; 459 ubyte *p = pmc.writePtr(); 460 uint len = cvMember(s, p); 461 pmc.written(len); 462 return 0; 463 } 464 465 466 void toDebug(StructDeclaration sd) 467 { 468 if (target.os != Target.OS.Windows) 469 return; 470 471 idx_t typidx1 = 0; 472 473 //printf("StructDeclaration::toDebug('%s')\n", sd.toChars()); 474 475 assert(config.fulltypes >= CV4); 476 if (sd.isAnonymous()) 477 return /*0*/; 478 479 if (typidx1) // if reference already generated 480 return /*typidx1*/; // use already existing reference 481 482 targ_size_t size; 483 uint property = 0; 484 if (!sd.members) 485 { 486 size = 0; 487 property |= 0x80; // forward reference 488 } 489 else 490 size = sd.structsize; 491 492 if (sd.parent.isAggregateDeclaration()) // if class is nested 493 property |= 8; 494 // if (st.Sctor || st.Sdtor) 495 // property |= 2; // class has ctors and/or dtors 496 // if (st.Sopoverload) 497 // property |= 4; // class has overloaded operators 498 // if (st.Scastoverload) 499 // property |= 0x40; // class has casting methods 500 // if (st.Sopeq && !(st.Sopeq.Sfunc.Fflags & Fnodebug)) 501 // property |= 0x20; // class has overloaded assignment 502 503 const char *id = sd.toPrettyChars(true); 504 505 uint leaf = sd.isUnionDeclaration() ? LF_UNION : LF_STRUCTURE; 506 if (config.fulltypes == CV8) 507 leaf = leaf == LF_UNION ? LF_UNION_V3 : LF_STRUCTURE_V3; 508 509 uint numidx; 510 final switch (leaf) 511 { 512 case LF_UNION: numidx = 8; break; 513 case LF_UNION_V3: numidx = 10; break; 514 case LF_STRUCTURE: numidx = 12; break; 515 case LF_STRUCTURE_V3: numidx = 18; break; 516 } 517 518 const len1 = numidx + cv4_numericbytes(cast(uint)size); 519 debtyp_t *d = debtyp_alloc(len1 + cv_stringbytes(id)); 520 cv4_storenumeric(d.data.ptr + numidx, cast(uint)size); 521 cv_namestring(d.data.ptr + len1, id); 522 523 if (leaf == LF_STRUCTURE) 524 { 525 TOWORD(d.data.ptr + 8,0); // dList 526 TOWORD(d.data.ptr + 10,0); // vshape is 0 (no virtual functions) 527 } 528 else if (leaf == LF_STRUCTURE_V3) 529 { 530 TOLONG(d.data.ptr + 10,0); // dList 531 TOLONG(d.data.ptr + 14,0); // vshape is 0 (no virtual functions) 532 } 533 TOWORD(d.data.ptr,leaf); 534 535 // Assign a number to prevent infinite recursion if a struct member 536 // references the same struct. 537 const length_save = d.length; 538 d.length = 0; // so cv_debtyp() will allocate new 539 const idx_t typidx = cv_debtyp(d); 540 d.length = length_save; // restore length 541 542 if (!sd.members) // if reference only 543 { 544 if (config.fulltypes == CV8) 545 { 546 TOWORD(d.data.ptr + 2,0); // count: number of fields is 0 547 TOLONG(d.data.ptr + 6,0); // field list is 0 548 TOWORD(d.data.ptr + 4,property); 549 } 550 else 551 { 552 TOWORD(d.data.ptr + 2,0); // count: number of fields is 0 553 TOWORD(d.data.ptr + 4,0); // field list is 0 554 TOWORD(d.data.ptr + 6,property); 555 } 556 return /*typidx*/; 557 } 558 559 // Compute the number of fields and the length of the fieldlist record 560 CvFieldList mc = CvFieldList(0, 0); 561 for (size_t i = 0; i < sd.members.length; i++) 562 { 563 Dsymbol s = (*sd.members)[i]; 564 s.apply(&cv_mem_count, &mc); 565 } 566 const uint nfields = mc.nfields; 567 568 // Generate fieldlist type record 569 mc.alloc(); 570 if (nfields) 571 { 572 for (size_t i = 0; i < sd.members.length; i++) 573 { 574 Dsymbol s = (*sd.members)[i]; 575 s.apply(&cv_mem_p, &mc); 576 } 577 } 578 579 //dbg_printf("fnamelen = %d, p-dt.data.ptr = %d\n",fnamelen,p-dt.data.ptr); 580 const idx_t fieldlist = mc.debtyp(); 581 582 TOWORD(d.data.ptr + 2, nfields); 583 if (config.fulltypes == CV8) 584 { 585 TOWORD(d.data.ptr + 4,property); 586 TOLONG(d.data.ptr + 6,fieldlist); 587 } 588 else 589 { 590 TOWORD(d.data.ptr + 4,fieldlist); 591 TOWORD(d.data.ptr + 6,property); 592 } 593 594 // cv4_outsym(s); 595 596 cv_udt(id, typidx); 597 598 // return typidx; 599 } 600 601 602 void toDebug(ClassDeclaration cd) 603 { 604 if (target.os != Target.OS.Windows) 605 return; 606 607 idx_t typidx1 = 0; 608 609 //printf("ClassDeclaration::toDebug('%s')\n", cd.toChars()); 610 611 assert(config.fulltypes >= CV4); 612 if (cd.isAnonymous()) 613 return /*0*/; 614 615 if (typidx1) // if reference already generated 616 return /*typidx1*/; // use already existing reference 617 618 targ_size_t size; 619 uint property = 0; 620 if (!cd.members) 621 { 622 size = 0; 623 property |= 0x80; // forward reference 624 } 625 else 626 size = cd.structsize; 627 628 if (cd.parent.isAggregateDeclaration()) // if class is nested 629 property |= 8; 630 if (cd.ctor || cd.dtor) 631 property |= 2; // class has ctors and/or dtors 632 // if (st.Sopoverload) 633 // property |= 4; // class has overloaded operators 634 // if (st.Scastoverload) 635 // property |= 0x40; // class has casting methods 636 // if (st.Sopeq && !(st.Sopeq.Sfunc.Fflags & Fnodebug)) 637 // property |= 0x20; // class has overloaded assignment 638 639 const id = cd.isCPPinterface() ? cd.ident.toChars() : cd.toPrettyChars(true); 640 const uint leaf = config.fulltypes == CV8 ? LF_CLASS_V3 : LF_CLASS; 641 642 const uint numidx = (leaf == LF_CLASS_V3) ? 18 : 12; 643 const uint len1 = numidx + cv4_numericbytes(cast(uint)size); 644 debtyp_t *d = debtyp_alloc(len1 + cv_stringbytes(id)); 645 cv4_storenumeric(d.data.ptr + numidx, cast(uint)size); 646 cv_namestring(d.data.ptr + len1, id); 647 648 idx_t vshapeidx = 0; 649 if (1) 650 { 651 const size_t dim = cd.vtbl.length; // number of virtual functions 652 if (dim) 653 { // 4 bits per descriptor 654 debtyp_t *vshape = debtyp_alloc(cast(uint)(4 + (dim + 1) / 2)); 655 TOWORD(vshape.data.ptr,LF_VTSHAPE); 656 TOWORD(vshape.data.ptr + 2, cast(uint)dim); 657 658 size_t n = 0; 659 ubyte descriptor = 0; 660 for (size_t i = 0; i < cd.vtbl.length; i++) 661 { 662 //if (intsize == 4) 663 descriptor |= 5; 664 vshape.data.ptr[4 + n / 2] = descriptor; 665 descriptor <<= 4; 666 n++; 667 } 668 vshapeidx = cv_debtyp(vshape); 669 } 670 } 671 if (leaf == LF_CLASS) 672 { 673 TOWORD(d.data.ptr + 8,0); // dList 674 TOWORD(d.data.ptr + 10,vshapeidx); 675 } 676 else if (leaf == LF_CLASS_V3) 677 { 678 TOLONG(d.data.ptr + 10,0); // dList 679 TOLONG(d.data.ptr + 14,vshapeidx); 680 } 681 TOWORD(d.data.ptr,leaf); 682 683 // Assign a number to prevent infinite recursion if a struct member 684 // references the same struct. 685 const length_save = d.length; 686 d.length = 0; // so cv_debtyp() will allocate new 687 const idx_t typidx = cv_debtyp(d); 688 d.length = length_save; // restore length 689 690 if (!cd.members) // if reference only 691 { 692 if (leaf == LF_CLASS_V3) 693 { 694 TOWORD(d.data.ptr + 2,0); // count: number of fields is 0 695 TOLONG(d.data.ptr + 6,0); // field list is 0 696 TOWORD(d.data.ptr + 4,property); 697 } 698 else 699 { 700 TOWORD(d.data.ptr + 2,0); // count: number of fields is 0 701 TOWORD(d.data.ptr + 4,0); // field list is 0 702 TOWORD(d.data.ptr + 6,property); 703 } 704 return /*typidx*/; 705 } 706 707 // Compute the number of fields and the length of the fieldlist record 708 CvFieldList mc = CvFieldList(0, 0); 709 710 /* Adding in the base classes causes VS 2010 debugger to refuse to display any 711 * of the fields. I have not been able to determine why. 712 * (Could it be because the base class is "forward referenced"?) 713 * It does work with VS 2012. 714 */ 715 bool addInBaseClasses = true; 716 if (addInBaseClasses) 717 { 718 // Add in base classes 719 for (size_t i = 0; i < cd.baseclasses.length; i++) 720 { 721 const bc = (*cd.baseclasses)[i]; 722 const uint elementlen = 4 + cgcv.sz_idx + cv4_numericbytes(bc.offset); 723 mc.count(cv_align(null, elementlen)); 724 } 725 } 726 727 for (size_t i = 0; i < cd.members.length; i++) 728 { 729 Dsymbol s = (*cd.members)[i]; 730 s.apply(&cv_mem_count, &mc); 731 } 732 const uint nfields = mc.nfields; 733 734 TOWORD(d.data.ptr + 2, nfields); 735 736 // Generate fieldlist type record 737 mc.alloc(); 738 739 if (nfields) // if we didn't overflow 740 { 741 if (addInBaseClasses) 742 { 743 ubyte* base = mc.writePtr(); 744 ubyte* p = base; 745 746 // Add in base classes 747 for (size_t i = 0; i < cd.baseclasses.length; i++) 748 { 749 BaseClass *bc = (*cd.baseclasses)[i]; 750 const idx_t typidx2 = cv4_typidx(Type_toCtype(bc.sym.type).Tnext); 751 const uint attribute = visibilityToCVAttr(Visibility.Kind.public_); 752 753 uint elementlen; 754 final switch (config.fulltypes) 755 { 756 case CV8: 757 TOWORD(p, LF_BCLASS_V2); 758 TOWORD(p + 2,attribute); 759 TOLONG(p + 4,typidx2); 760 elementlen = 8; 761 break; 762 763 case CV4: 764 TOWORD(p, LF_BCLASS); 765 TOWORD(p + 2,typidx2); 766 TOWORD(p + 4,attribute); 767 elementlen = 6; 768 break; 769 } 770 771 cv4_storenumeric(p + elementlen, bc.offset); 772 elementlen += cv4_numericbytes(bc.offset); 773 p += cv_align(p + elementlen, elementlen); 774 } 775 mc.written(cast(uint)(p - base)); 776 } 777 778 foreach(s; (*cd.members)[]) 779 s.apply(&cv_mem_p, &mc); 780 } 781 782 const idx_t fieldlist = mc.debtyp(); 783 784 if (config.fulltypes == CV8) 785 { 786 TOWORD(d.data.ptr + 4,property); 787 TOLONG(d.data.ptr + 6,fieldlist); 788 } 789 else 790 { 791 TOWORD(d.data.ptr + 4,fieldlist); 792 TOWORD(d.data.ptr + 6,property); 793 } 794 795 // cv4_outsym(s); 796 797 cv_udt(id, typidx); 798 799 // return typidx; 800 } 801 802 private uint writeField(ubyte* p, const char* id, uint attr, uint typidx, uint offset) 803 { 804 if (config.fulltypes == CV8) 805 { 806 TOWORD(p,LF_MEMBER_V3); 807 TOWORD(p + 2,attr); 808 TOLONG(p + 4,typidx); 809 cv4_storesignednumeric(p + 8, offset); 810 uint len = 8 + cv4_signednumericbytes(offset); 811 len += cv_namestring(p + len, id); 812 return cv_align(p + len, len); 813 } 814 else 815 { 816 TOWORD(p,LF_MEMBER); 817 TOWORD(p + 2,typidx); 818 TOWORD(p + 4,attr); 819 cv4_storesignednumeric(p + 6, offset); 820 uint len = 6 + cv4_signednumericbytes(offset); 821 return len + cv_namestring(p + len, id); 822 } 823 } 824 825 void toDebugClosure(Symbol* closstru) 826 { 827 if (target.os != Target.OS.Windows) 828 return; 829 830 //printf("toDebugClosure('%s')\n", fd.toChars()); 831 832 assert(config.fulltypes >= CV4); 833 834 uint leaf = config.fulltypes == CV8 ? LF_STRUCTURE_V3 : LF_STRUCTURE; 835 uint numidx = leaf == LF_STRUCTURE ? 12 : 18; 836 uint structsize = cast(uint)(closstru.Sstruct.Sstructsize); 837 const char* closname = closstru.Sident.ptr; 838 839 const len1 = numidx + cv4_numericbytes(structsize); 840 debtyp_t *d = debtyp_alloc(len1 + cv_stringbytes(closname)); 841 cv4_storenumeric(d.data.ptr + numidx, structsize); 842 cv_namestring(d.data.ptr + len1, closname); 843 844 if (leaf == LF_STRUCTURE) 845 { 846 TOWORD(d.data.ptr + 8,0); // dList 847 TOWORD(d.data.ptr + 10,0); // vshape is 0 (no virtual functions) 848 } 849 else // LF_STRUCTURE_V3 850 { 851 TOLONG(d.data.ptr + 10,0); // dList 852 TOLONG(d.data.ptr + 14,0); // vshape is 0 (no virtual functions) 853 } 854 TOWORD(d.data.ptr,leaf); 855 856 // Assign a number to prevent infinite recursion if a struct member 857 // references the same struct. 858 const length_save = d.length; 859 d.length = 0; // so cv_debtyp() will allocate new 860 const idx_t typidx = cv_debtyp(d); 861 d.length = length_save; // restore length 862 863 // Compute the number of fields (nfields), and the length of the fieldlist record (flistlen) 864 uint nfields = 0; 865 uint flistlen = 2; 866 for (auto sl = closstru.Sstruct.Sfldlst; sl; sl = list_next(sl)) 867 { 868 Symbol *sf = list_symbol(sl); 869 uint thislen = (config.fulltypes == CV8 ? 8 : 6); 870 thislen += cv4_signednumericbytes(cast(uint)sf.Smemoff); 871 thislen += cv_stringbytes(sf.Sident.ptr); 872 thislen = cv_align(null, thislen); 873 874 if (config.fulltypes != CV8 && flistlen + thislen > CV4_NAMELENMAX) 875 break; // Too long, fail gracefully 876 877 flistlen += thislen; 878 nfields++; 879 } 880 881 // Generate fieldlist type record 882 debtyp_t *dt = debtyp_alloc(flistlen); 883 ubyte *p = dt.data.ptr; 884 885 // And fill it in 886 TOWORD(p, config.fulltypes == CV8 ? LF_FIELDLIST_V2 : LF_FIELDLIST); 887 uint flistoff = 2; 888 for (auto sl = closstru.Sstruct.Sfldlst; sl && flistoff < flistlen; sl = list_next(sl)) 889 { 890 Symbol *sf = list_symbol(sl); 891 idx_t vtypidx = cv_typidx(sf.Stype); 892 flistoff += writeField(p + flistoff, sf.Sident.ptr, 3 /*public*/, vtypidx, cast(uint)sf.Smemoff); 893 } 894 895 //dbg_printf("fnamelen = %d, p-dt.data.ptr = %d\n",fnamelen,p-dt.data.ptr); 896 assert(flistoff == flistlen); 897 const idx_t fieldlist = cv_debtyp(dt); 898 899 uint property = 0; 900 TOWORD(d.data.ptr + 2, nfields); 901 if (config.fulltypes == CV8) 902 { 903 TOWORD(d.data.ptr + 4,property); 904 TOLONG(d.data.ptr + 6,fieldlist); 905 } 906 else 907 { 908 TOWORD(d.data.ptr + 4,fieldlist); 909 TOWORD(d.data.ptr + 6,property); 910 } 911 912 cv_udt(closname, typidx); 913 } 914 915 /* ===================================================================== */ 916 917 /***************************************** 918 * Insert CV info into *p. 919 * Returns: 920 * number of bytes written, or that would be written if p==null 921 */ 922 923 int cvMember(Dsymbol s, ubyte *p) 924 { 925 scope v = new CVMember(p); 926 s.accept(v); 927 return v.result; 928 } 929 private extern (C++) class CVMember : Visitor 930 { 931 ubyte *p; 932 int result; 933 934 this(ubyte *p) @safe 935 { 936 this.p = p; 937 result = 0; 938 } 939 940 alias visit = Visitor.visit; 941 942 override void visit(Dsymbol s) 943 { 944 } 945 946 void cvMemberCommon(Dsymbol s, const(char)* id, idx_t typidx) 947 { 948 if (!p) 949 result = cv_stringbytes(id); 950 951 switch (config.fulltypes) 952 { 953 case CV8: 954 if (!p) 955 { 956 result += 8; 957 result = cv_align(null, result); 958 } 959 else 960 { 961 TOWORD(p,LF_NESTTYPE_V3); 962 TOWORD(p + 2,0); 963 TOLONG(p + 4,typidx); 964 result = 8 + cv_namestring(p + 8, id); 965 result = cv_align(p + result, result); 966 } 967 break; 968 969 case CV4: 970 if (!p) 971 { 972 result += 4; 973 } 974 else 975 { 976 TOWORD(p,LF_NESTTYPE); 977 TOWORD(p + 2,typidx); 978 result = 4 + cv_namestring(p + 4, id); 979 } 980 break; 981 982 default: 983 assert(0); 984 } 985 debug 986 { 987 if (p) 988 { 989 int save = result; 990 p = null; 991 cvMemberCommon(s, id, typidx); 992 assert(result == save); 993 } 994 } 995 } 996 997 override void visit(EnumDeclaration ed) 998 { 999 //printf("EnumDeclaration.cvMember() '%s'\n", d.toChars()); 1000 1001 cvMemberCommon(ed, ed.toChars(), cv4_Denum(ed)); 1002 } 1003 1004 override void visit(FuncDeclaration fd) 1005 { 1006 //printf("FuncDeclaration.cvMember() '%s'\n", fd.toChars()); 1007 1008 if (!fd.type) // if not compiled in, 1009 return; // skip it 1010 if (!fd.type.nextOf()) // if not fully analyzed (e.g. auto return type) 1011 return; // skip it 1012 1013 const id = fd.toChars(); 1014 1015 if (!p) 1016 { 1017 result = 2 + 2 + cgcv.sz_idx + cv_stringbytes(id); 1018 result = cv_align(null, result); 1019 return; 1020 } 1021 else 1022 { 1023 int count = 0; 1024 int mlen = 2; 1025 { 1026 if (fd.isIntroducing()) 1027 mlen += 4; 1028 mlen += cgcv.sz_idx * 2; 1029 count++; 1030 } 1031 1032 // Allocate and fill it in 1033 debtyp_t *d = debtyp_alloc(mlen); 1034 ubyte *q = d.data.ptr; 1035 TOWORD(q,config.fulltypes == CV8 ? LF_METHODLIST_V2 : LF_METHODLIST); 1036 q += 2; 1037 // for (s = sf; s; s = s.Sfunc.Foversym) 1038 { 1039 uint attribute = visibilityToCVAttr(fd.visible().kind); 1040 1041 /* 0*4 vanilla method 1042 * 1*4 virtual method 1043 * 2*4 static method 1044 * 3*4 friend method 1045 * 4*4 introducing virtual method 1046 * 5*4 pure virtual method 1047 * 6*4 pure introducing virtual method 1048 * 7*4 reserved 1049 */ 1050 1051 if (fd.isStatic()) 1052 attribute |= 2*4; 1053 else if (fd.isVirtual()) 1054 { 1055 if (fd.isIntroducing()) 1056 { 1057 if (fd.isAbstract()) 1058 attribute |= 6*4; 1059 else 1060 attribute |= 4*4; 1061 } 1062 else 1063 { 1064 if (fd.isAbstract()) 1065 attribute |= 5*4; 1066 else 1067 attribute |= 1*4; 1068 } 1069 } 1070 else 1071 attribute |= 0*4; 1072 1073 TOIDX(q,attribute); 1074 q += cgcv.sz_idx; 1075 TOIDX(q, cv4_memfunctypidx(fd)); 1076 q += cgcv.sz_idx; 1077 if (fd.isIntroducing()) 1078 { 1079 TOLONG(q, fd.vtblIndex * target.ptrsize); 1080 q += 4; 1081 } 1082 } 1083 assert(q - d.data.ptr == mlen); 1084 1085 idx_t typidx = cv_debtyp(d); 1086 if (typidx) 1087 { 1088 switch (config.fulltypes) 1089 { 1090 case CV8: 1091 TOWORD(p,LF_METHOD_V3); 1092 goto Lmethod; 1093 case CV4: 1094 TOWORD(p,LF_METHOD); 1095 Lmethod: 1096 TOWORD(p + 2,count); 1097 result = 4; 1098 TOIDX(p + result, typidx); 1099 result += cgcv.sz_idx; 1100 result += cv_namestring(p + result, id); 1101 break; 1102 1103 default: 1104 assert(0); 1105 } 1106 } 1107 result = cv_align(p + result, result); 1108 debug 1109 { 1110 int save = result; 1111 result = 0; 1112 p = null; 1113 visit(fd); 1114 assert(result == save); 1115 } 1116 } 1117 } 1118 1119 override void visit(VarDeclaration vd) 1120 { 1121 //printf("VarDeclaration.cvMember(p = %p) '%s'\n", p, vd.toChars()); 1122 1123 if (vd.type.toBasetype().ty == Ttuple) 1124 return; 1125 1126 const id = vd.toChars(); 1127 1128 if (!p) 1129 { 1130 if (vd.isField()) 1131 { 1132 if (config.fulltypes == CV8) 1133 result += 2; 1134 result += 6 + cv_stringbytes(id); 1135 result += cv4_numericbytes(vd.offset); 1136 } 1137 else if (vd.isStatic()) 1138 { 1139 if (config.fulltypes == CV8) 1140 result += 2; 1141 result += 6 + cv_stringbytes(id); 1142 } 1143 result = cv_align(null, result); 1144 } 1145 else 1146 { 1147 idx_t typidx = cv_typidx(Type_toCtype(vd.type)); 1148 uint attribute = visibilityToCVAttr(vd.visible().kind); 1149 assert((attribute & ~3) == 0); 1150 switch (config.fulltypes) 1151 { 1152 case CV8: 1153 if (vd.isField()) 1154 { 1155 TOWORD(p,LF_MEMBER_V3); 1156 TOWORD(p + 2,attribute); 1157 TOLONG(p + 4,typidx); 1158 cv4_storenumeric(p + 8, vd.offset); 1159 result = 8 + cv4_numericbytes(vd.offset); 1160 result += cv_namestring(p + result, id); 1161 } 1162 else if (vd.isStatic()) 1163 { 1164 TOWORD(p,LF_STMEMBER_V3); 1165 TOWORD(p + 2,attribute); 1166 TOLONG(p + 4,typidx); 1167 result = 8; 1168 result += cv_namestring(p + result, id); 1169 } 1170 break; 1171 1172 case CV4: 1173 if (vd.isField()) 1174 { 1175 TOWORD(p,LF_MEMBER); 1176 TOWORD(p + 2,typidx); 1177 TOWORD(p + 4,attribute); 1178 cv4_storenumeric(p + 6, vd.offset); 1179 result = 6 + cv4_numericbytes(vd.offset); 1180 result += cv_namestring(p + result, id); 1181 } 1182 else if (vd.isStatic()) 1183 { 1184 TOWORD(p,LF_STMEMBER); 1185 TOWORD(p + 2,typidx); 1186 TOWORD(p + 4,attribute); 1187 result = 6; 1188 result += cv_namestring(p + result, id); 1189 } 1190 break; 1191 1192 default: 1193 assert(0); 1194 } 1195 1196 result = cv_align(p + result, result); 1197 debug 1198 { 1199 int save = result; 1200 result = 0; 1201 p = null; 1202 visit(vd); 1203 assert(result == save); 1204 } 1205 } 1206 } 1207 }