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