1 /**
2  * CodeView 4 symbolic debug info generation
3  *
4  * Compiler implementation of the
5  * $(LINK2 https://www.dlang.org, D programming language).
6  *
7  * Copyright:   Copyright (C) 1984-1995 by Symantec
8  *              Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved
9  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
10  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/dcgcv.d, backend/dcgcv.d)
12  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/dcgcv.d
13  */
14 
15 module dmd.backend.dcgcv;
16 
17 version (SCPP)
18     version = COMPILE;
19 version (MARS)
20     version = COMPILE;
21 
22 version (COMPILE)
23 {
24 
25 import core.stdc.stdio;
26 import core.stdc.stdlib;
27 import core.stdc.string;
28 
29 import dmd.backend.cc;
30 import dmd.backend.cdef;
31 import dmd.backend.cgcv;
32 import dmd.backend.code;
33 import dmd.backend.code_x86;
34 import dmd.backend.cv4;
35 import dmd.backend.dlist;
36 import dmd.backend.dvec;
37 import dmd.backend.el;
38 import dmd.backend.global;
39 import dmd.backend.mem;
40 import dmd.backend.obj;
41 import dmd.backend.symtab;
42 import dmd.backend.ty;
43 import dmd.backend.type;
44 
45 import dmd.backend.barray;
46 
47 import dmd.common.outbuffer;
48 
49 version (SCPP)
50 {
51     import cpp;
52     import msgs2;
53     import parser;
54 }
55 version (MARS)
56 {
57     import dmd.backend.dvarstats;
58 }
59 
60 extern (C++):
61 
62 nothrow:
63 @safe:
64 
65 @trusted
66 extern (C) void TOOFFSET(void* p, targ_size_t value)
67 {
68     switch (_tysize[TYnptr])
69     {
70         case 2: *cast(ushort*)p = cast(ushort)value; break;
71         case 4: *cast(uint*)  p = cast(uint)  value; break;
72         case 8: *cast(ulong*) p = cast(ulong) value; break;
73         default:
74             assert(0);
75     }
76 }
77 
78 extern __gshared char* ftdbname;
79 
80 // Convert from SFL visibilities to CV4 protections
81 uint SFLtoATTR(uint sfl) { return 4 - ((sfl & SFLpmask) >> 5); }
82 
83 __gshared
84 {
85 
86 /* Dynamic array of debtyp_t's  */
87 private Barray!(debtyp_t*) debtyp;
88 
89 private vec_t debtypvec;     // vector of used entries
90 enum DEBTYPVECDIM = 16_001;   //8009 //3001     // dimension of debtypvec (should be prime)
91 
92 enum DEBTYPHASHDIM = 1009;
93 private uint[DEBTYPHASHDIM] debtyphash;
94 
95 private OutBuffer *reset_symbuf; // Keep pointers to reset symbols
96 
97 @trusted
98 idx_t DEB_NULL() { return cgcv.deb_offset; }        // index of null debug type record
99 
100 /* This limitation is because of 4K page sizes
101  * in optlink/cv/cvhashes.asm
102  */
103 enum CVIDMAX = (0xFF0-20);   // the -20 is picked by trial and error
104 
105 enum LOCATsegrel = 0xC000;
106 
107 /* Unfortunately, the fixup stuff is different for EASY OMF and Microsoft */
108 enum EASY_LCFDoffset  =      (LOCATsegrel | 0x1404);
109 enum EASY_LCFDpointer =      (LOCATsegrel | 0x1800);
110 
111 enum LCFD32offset     =      (LOCATsegrel | 0x2404);
112 enum LCFD32pointer    =      (LOCATsegrel | 0x2C00);
113 enum LCFD16pointer    =      (LOCATsegrel | 0x0C00);
114 
115 version (MARS)
116     extern Cgcv cgcv; // already declared in cgcv.d
117 else
118     Cgcv cgcv;
119 
120 }
121 
122 version (MARS)
123     enum MARS = true;
124 else
125     enum MARS = false;
126 
127 /******************************************
128  * Return number of bytes consumed in OBJ file by a name.
129  */
130 
131 @trusted
132 int cv_stringbytes(const(char)* name)
133 {
134     int len = cast(int)strlen(name);
135     if (config.fulltypes == CV8)
136         return len + 1;
137     if (len > CVIDMAX)
138         len = CVIDMAX;
139     return len + ((len > 255) ? 4 : 1);
140 }
141 
142 /******************************************
143  * Stuff a namestring into p.
144  * Returns:
145  *      number of bytes consumed
146  */
147 
148 @trusted
149 int cv_namestring(ubyte *p, const(char)* name, int length = -1)
150 {
151     size_t len = (length >= 0) ? length : strlen(name);
152     if (config.fulltypes == CV8)
153     {
154         size_t numBytesWritten = len + ((length < 0) ? 1 : 0);
155         memcpy(p, name, numBytesWritten);
156         if(config.flags2 & CFG2gms)
157         {
158             for(int i = 0; i < len; i++)
159             {
160                 if(p[i] == '.')
161                     p[i] = '@';
162             }
163         }
164         return cast(int)numBytesWritten;
165     }
166     if (len > 255)
167     {   p[0] = 0xFF;
168         p[1] = 0;
169         if (len > CVIDMAX)
170             len = CVIDMAX;
171         TOWORD(p + 2,cast(uint)len);
172         memcpy(p + 4,name,len);
173         len += 4;
174     }
175     else
176     {   p[0] = cast(ubyte)len;
177         memcpy(p + 1,name,len);
178         len++;
179     }
180     return cast(int)len;
181 }
182 
183 /***********************************
184  * Compute debug register number for symbol s.
185  * Returns:
186  *      0..7    byte registers
187  *      8..15   word registers
188  *      16..23  dword registers
189  */
190 
191 @trusted
192 private int cv_regnum(Symbol *s)
193 {
194     uint reg = s.Sreglsw;
195     if (s.Sclass == SC.pseudo)
196     {
197 version (SCPP)
198         reg = pseudoreg[reg];
199     }
200     else
201     {
202         assert(reg < 8);
203         assert(s.Sfl == FLreg);
204         switch (type_size(s.Stype))
205         {
206             case LONGSIZE:
207             case 3:             reg += 8;
208                                 goto case;
209 
210             case SHORTSIZE:     reg += 8;
211                                 goto case;
212 
213             case CHARSIZE:      break;
214 
215             case LLONGSIZE:
216                 reg += (s.Sregmsw << 8) + (16 << 8) + 16;
217                 if (config.fulltypes == CV4)
218                     reg += (1 << 8);
219                 break;
220 
221             default:
222 static if (0)
223 {
224                 symbol_print(s);
225                 type_print(s.Stype);
226                 printf("size = %d\n",type_size(s.Stype));
227 }
228                 assert(0);
229         }
230     }
231     if (config.fulltypes == CV4)
232         reg++;
233     return reg;
234 }
235 
236 /***********************************
237  * Allocate a debtyp_t.
238  */
239 @trusted
240 debtyp_t * debtyp_alloc(uint length)
241 {
242     debtyp_t *d;
243     uint pad = 0;
244 
245     //printf("len = %u, x%x\n", length, length);
246     if (config.fulltypes == CV8)
247     {   // length+2 must lie on 4 byte boundary
248         pad = ((length + 2 + 3) & ~3) - (length + 2);
249         length += pad;
250     }
251 
252     if (length > ushort.max)
253         err_nomem();
254 
255     const len = debtyp_t.sizeof - (d.data).sizeof + length;
256 debug
257 {
258     d = cast(debtyp_t *) mem_malloc(len /*+ 1*/);
259     memset(d, 0xAA, len);
260 //    (cast(char*)d)[len] = 0x2E;
261 }
262 else
263 {
264     d = cast(debtyp_t *) malloc(debtyp_t.sizeof - (d.data).sizeof + length);
265     if (!d)
266         err_nomem();
267 }
268     d.length = cast(ushort)length;
269     if (pad)
270     {
271         __gshared const ubyte[3] padx = [0xF3, 0xF2, 0xF1];
272         memcpy(d.data.ptr + length - pad, padx.ptr + 3 - pad, pad);
273     }
274     //printf("debtyp_alloc(%d) = %p\n", length, d);
275     return d;
276 }
277 
278 /***********************************
279  * Free a debtyp_t.
280  */
281 
282 @trusted
283 private void debtyp_free(debtyp_t *d)
284 {
285     //printf("debtyp_free(length = %d, %p)\n", d.length, d);
286     //fflush(stdout);
287 debug
288 {
289     assert(d.length <= ushort.max);
290     uint len = debtyp_t.sizeof - (d.data).sizeof + d.length;
291 //    assert((cast(char*)d)[len] == 0x2E);
292     memset(d, 0x55, len);
293     mem_free(d);
294 }
295 else
296 {
297     free(d);
298 }
299 }
300 
301 static if (0)
302 {
303 void debtyp_check(debtyp_t *d,int linnum)
304 {   int i;
305     __gshared char c;
306 
307     //printf("linnum = %d\n",linnum);
308     //printf(" length = %d\n",d.length);
309     for (i = 0; i < d.length; i++)
310         c = d.data.ptr[i];
311 }
312 
313 void debtyp_check(debtyp_t* d) { debtyp_check(d,__LINE__); }
314 }
315 else
316 {
317 void debtyp_check(debtyp_t* d) { }
318 }
319 
320 /***********************************
321  * Search for debtyp_t in debtyp[]. If it is there, return the index
322  * of it, and free d. Otherwise, add it.
323  * Returns:
324  *      index in debtyp[]
325  */
326 
327 @trusted
328 idx_t cv_debtyp(debtyp_t *d)
329 {
330     uint hashi;
331 
332     assert(d);
333     const length = d.length;
334     //printf("length = %3d\n",length);
335     if (length)
336     {
337         uint hash = length;
338         if (length >= uint.sizeof)
339         {
340             // Hash consists of the sum of the first 4 bytes with the last 4 bytes
341             union U { ubyte* cp; uint* up; }
342             U un = void;
343             un.cp = d.data.ptr;
344             hash += *un.up;
345             un.cp += length - uint.sizeof;
346             hash += *un.up;
347         }
348         hashi = hash % DEBTYPHASHDIM;
349         hash %= DEBTYPVECDIM;
350 //printf(" hashi = %d", hashi);
351 
352         if (vec_testbit(hash,debtypvec))
353         {
354 //printf(" test");
355             // Threaded list is much faster
356             for (uint u = debtyphash[hashi]; u; u = debtyp[u].prev)
357             //for (uint u = debtyp.length; u--; )
358             {
359                 if (length == debtyp[u].length &&
360                     memcmp(d.data.ptr,debtyp[u].data.ptr,length) == 0)
361                 {   debtyp_free(d);
362 //printf(" match %d\n",u);
363                     return u + cgcv.deb_offset;
364                 }
365             }
366         }
367         else
368             vec_setbit(hash,debtypvec);
369     }
370     else
371         hashi = 1;
372 //printf(" add   %d\n",debtyp.length);
373     d.prev = debtyphash[hashi];
374     debtyphash[hashi] = cast(uint)debtyp.length;
375 
376     /* It's not already in the array, so add it */
377     debtyp.push(d);
378     version (SCPP)
379     {
380         if (debtyp.length >= 0xE000)
381             err_fatal(EM_2manytypes,0xE000);         // too many types
382     }
383 
384     return cast(uint)debtyp.length - 1 + cgcv.deb_offset;
385 }
386 
387 @trusted
388 idx_t cv_numdebtypes()
389 {
390     return cast(idx_t)debtyp.length;
391 }
392 
393 /****************************
394  * Store a null record at DEB_NULL.
395  */
396 
397 @trusted
398 void cv_init()
399 {   debtyp_t *d;
400 
401     //printf("cv_init()\n");
402 
403     // Initialize statics
404     debtyp.setLength(0);
405     if (!ftdbname)
406         ftdbname = cast(char *)"symc.tdb".ptr;
407 
408     memset(&cgcv,0,cgcv.sizeof);
409     cgcv.sz_idx = 2;
410     cgcv.LCFDoffset = LCFD32offset;
411     cgcv.LCFDpointer = LCFD16pointer;
412 
413     debtypvec = vec_calloc(DEBTYPVECDIM);
414     memset(debtyphash.ptr,0,debtyphash.sizeof);
415 
416     if (reset_symbuf)
417     {
418         Symbol **p = cast(Symbol **)reset_symbuf.buf;
419         const size_t n = reset_symbuf.length() / (Symbol *).sizeof;
420         for (size_t i = 0; i < n; ++i)
421             symbol_reset(p[i]);
422         reset_symbuf.reset();
423     }
424     else
425     {
426         reset_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
427         if (!reset_symbuf)
428             err_nomem();
429         reset_symbuf.reserve(10 * (Symbol*).sizeof);
430     }
431 
432     /* Reset for different OBJ file formats     */
433     if (I32 || I64)
434     {
435         // Adjust values in old CV tables for 32 bit ints
436         dttab[TYenum] = dttab[TYlong];
437         dttab[TYint]  = dttab[TYlong];
438         dttab[TYuint] = dttab[TYulong];
439 
440         // Adjust Codeview 4 values for 32 bit ints and 32 bit pointer offsets
441         dttab4[TYenum] = 0x74;
442         dttab4[TYint]  = 0x74;
443         dttab4[TYuint] = 0x75;
444         if (I64)
445         {
446             dttab4[TYptr]  = 0x600;
447             dttab4[TYnptr] = 0x600;
448             dttab4[TYsptr] = 0x600;
449             dttab4[TYimmutPtr] = 0x600;
450             dttab4[TYsharePtr] = 0x600;
451             dttab4[TYrestrictPtr] = 0x600;
452             dttab4[TYfgPtr] = 0x600;
453         }
454         else
455         {
456             dttab4[TYptr]  = 0x400;
457             dttab4[TYsptr] = 0x400;
458             dttab4[TYnptr] = 0x400;
459             dttab4[TYimmutPtr] = 0x400;
460             dttab4[TYsharePtr] = 0x400;
461             dttab4[TYrestrictPtr] = 0x400;
462             dttab4[TYfgPtr] = 0x400;
463         }
464         dttab4[TYcptr] = 0x400;
465         dttab4[TYfptr] = 0x500;
466 
467         if (config.flags & CFGeasyomf)
468         {   cgcv.LCFDoffset  = EASY_LCFDoffset;
469             cgcv.LCFDpointer = EASY_LCFDpointer;
470             assert(config.fulltypes == CVOLD);
471         }
472         else
473             cgcv.LCFDpointer = LCFD32pointer;
474 
475         if (config.exe & EX_flat)
476             cgcv.FD_code = 0x10;
477     }
478 
479     if (config.fulltypes >= CV4)
480     {   int flags;
481         __gshared ushort[5] memmodel = [0,0x100,0x20,0x120,0x120];
482         char[1 + (VERSION).sizeof] version_;
483         ubyte[8 + (version_).sizeof] debsym;
484 
485         // Put out signature indicating CV4 format
486         switch (config.fulltypes)
487         {
488             case CV4:
489                 cgcv.signature = 1;
490                 break;
491 
492             case CV8:
493                 cgcv.signature = 4;
494                 break;
495 
496             default:
497             {   const(char)* x = "1MYS";
498                 cgcv.signature = *cast(int *) x;
499                 break;
500             }
501         }
502 
503         cgcv.deb_offset = 0x1000;
504 
505         if (config.fulltypes == CV8)
506         {   cgcv.sz_idx = 4;
507             return;     // figure out rest later
508         }
509 
510         if (config.fulltypes >= CVSYM)
511         {   cgcv.sz_idx = 4;
512             if (!(config.flags2 & CFG2phgen))
513                 cgcv.deb_offset = 0x80000000;
514         }
515 
516         objmod.write_bytes(SegData[DEBSYM],4,&cgcv.signature);
517 
518         // Allocate an LF_ARGLIST with no arguments
519         if (config.fulltypes == CV4)
520         {   d = debtyp_alloc(4);
521             TOWORD(d.data.ptr,LF_ARGLIST);
522             TOWORD(d.data.ptr + 2,0);
523         }
524         else
525         {   d = debtyp_alloc(6);
526             TOWORD(d.data.ptr,LF_ARGLIST);
527             TOLONG(d.data.ptr + 2,0);
528         }
529 
530         // Put out S_COMPILE record
531         TOWORD(debsym.ptr + 2,S_COMPILE);
532         switch (config.target_cpu)
533         {
534             case TARGET_8086:   debsym[4] = 0;  break;
535             case TARGET_80286:  debsym[4] = 2;  break;
536             case TARGET_80386:  debsym[4] = 3;  break;
537             case TARGET_80486:  debsym[4] = 4;  break;
538 
539             case TARGET_Pentium:
540             case TARGET_PentiumMMX:
541                                 debsym[4] = 5;  break;
542 
543             case TARGET_PentiumPro:
544             case TARGET_PentiumII:
545                                 debsym[4] = 6;  break;
546             default:    assert(0);
547         }
548         debsym[5] = (CPP != 0);         // 0==C, 1==C++
549         flags = (config.inline8087) ? (0<<3) : (1<<3);
550         if (I32)
551             flags |= 0x80;              // 32 bit addresses
552         flags |= memmodel[config.memmodel];
553         TOWORD(debsym.ptr + 6,flags);
554         version_[0] = 'Z';
555         strcpy(version_.ptr + 1,VERSION);
556         cv_namestring(debsym.ptr + 8,version_.ptr);
557         TOWORD(debsym.ptr,6 + (version_).sizeof);
558         objmod.write_bytes(SegData[DEBSYM],8 + (version_).sizeof,debsym.ptr);
559 
560     }
561     else
562     {
563         assert(0);
564     }
565     if (config.fulltypes == CVTDB)
566         cgcv.deb_offset = cv_debtyp(d);
567     else
568         cv_debtyp(d);
569 }
570 
571 /////////////////////////// CodeView 4 ///////////////////////////////
572 
573 /***********************************
574  * Return number of bytes required to store a numeric leaf.
575  */
576 
577 uint cv4_numericbytes(uint value)
578 {   uint u;
579 
580     if (value < 0x8000)
581         u = 2;
582     else if (value < 0x10000)
583         u = 4;
584     else
585         u = 6;
586     return u;
587 }
588 
589 /********************************
590  * Store numeric leaf.
591  * Must use exact same number of bytes as cv4_numericbytes().
592  */
593 
594 @trusted
595 void cv4_storenumeric(ubyte *p, uint value)
596 {
597     if (value < 0x8000)
598         TOWORD(p,value);
599     else if (value < 0x10000)
600     {   TOWORD(p,LF_USHORT);
601         p += 2;
602         TOWORD(p,value);
603     }
604     else
605     {   TOWORD(p,LF_ULONG);
606         *cast(targ_ulong *)(p + 2) = cast(uint) value;
607     }
608 }
609 
610 /***********************************
611  * Return number of bytes required to store a signed numeric leaf.
612  * Params:
613  *   value = value to store
614  * Returns:
615  *   number of bytes required for storing value
616  */
617 uint cv4_signednumericbytes(int value)
618 {
619     uint u;
620     if (value >= 0 && value < 0x8000)
621         u = 2;
622     else if (value == cast(short)value)
623         u = 4;
624     else
625         u = 6;
626     return u;
627 }
628 
629 /********************************
630  * Store signed numeric leaf.
631  * Must use exact same number of bytes as cv4_signednumericbytes().
632  * Params:
633  *   p = address where to store value
634  *   value = value to store
635  */
636 @trusted
637 void cv4_storesignednumeric(ubyte *p, int value)
638 {
639     if (value >= 0 && value < 0x8000)
640         TOWORD(p, value);
641     else if (value == cast(short)value)
642     {
643         TOWORD(p, LF_SHORT);
644         TOWORD(p + 2, value);
645     }
646     else
647     {
648         TOWORD(p,LF_LONG);
649         TOLONG(p + 2, value);
650     }
651 }
652 
653 /*********************************
654  * Generate a type index for a parameter list.
655  */
656 
657 @trusted
658 idx_t cv4_arglist(type *t,uint *pnparam)
659 {   uint u;
660     uint nparam;
661     idx_t paramidx;
662     debtyp_t *d;
663     param_t *p;
664 
665     // Compute nparam, number of parameters
666     nparam = 0;
667     for (p = t.Tparamtypes; p; p = p.Pnext)
668         nparam++;
669     *pnparam = nparam;
670 
671     // Construct an LF_ARGLIST of those parameters
672     if (nparam == 0)
673     {
674         if (config.fulltypes == CV8)
675         {
676             d = debtyp_alloc(2 + 4 + 4);
677             TOWORD(d.data.ptr,LF_ARGLIST_V2);
678             TOLONG(d.data.ptr + 2,1);
679             TOLONG(d.data.ptr + 6,0);
680             paramidx = cv_debtyp(d);
681         }
682         else
683             paramidx = DEB_NULL;
684     }
685     else
686     {
687         switch (config.fulltypes)
688         {
689             case CV8:
690                 d = debtyp_alloc(2 + 4 + nparam * 4);
691                 TOWORD(d.data.ptr,LF_ARGLIST_V2);
692                 TOLONG(d.data.ptr + 2,nparam);
693 
694                 p = t.Tparamtypes;
695                 for (u = 0; u < nparam; u++)
696                 {   TOLONG(d.data.ptr + 6 + u * 4,cv4_typidx(p.Ptype));
697                     p = p.Pnext;
698                 }
699                 break;
700 
701             case CV4:
702                 d = debtyp_alloc(2 + 2 + nparam * 2);
703                 TOWORD(d.data.ptr,LF_ARGLIST);
704                 TOWORD(d.data.ptr + 2,nparam);
705 
706                 p = t.Tparamtypes;
707                 for (u = 0; u < nparam; u++)
708                 {   TOWORD(d.data.ptr + 4 + u * 2,cv4_typidx(p.Ptype));
709                     p = p.Pnext;
710                 }
711                 break;
712 
713             default:
714                 d = debtyp_alloc(2 + 4 + nparam * 4);
715                 TOWORD(d.data.ptr,LF_ARGLIST);
716                 TOLONG(d.data.ptr + 2,nparam);
717 
718                 p = t.Tparamtypes;
719                 for (u = 0; u < nparam; u++)
720                 {   TOLONG(d.data.ptr + 6 + u * 4,cv4_typidx(p.Ptype));
721                     p = p.Pnext;
722                 }
723                 break;
724         }
725         paramidx = cv_debtyp(d);
726     }
727     return paramidx;
728 }
729 
730 /*****************************
731  * Build LF_METHODLIST for overloaded member function.
732  * Output:
733  *      *pcount         # of entries in method list
734  * Returns:
735  *      type index of method list
736  *      0 don't do this one
737  */
738 
739 version (SCPP)
740 {
741 
742 private int cv4_methodlist(Symbol *sf,int *pcount)
743 {   int count;
744     int mlen;
745     Symbol *s;
746     debtyp_t *d;
747     ubyte *p;
748     ushort attribute;
749 
750     symbol_debug(sf);
751 
752     // First, compute how big the method list is
753     count = 0;
754     mlen = 2;
755     for (s = sf; s; s = s.Sfunc.Foversym)
756     {
757         if (s.Sclass == SC.typedef_ || s.Sclass == SC.functempl)
758             continue;
759         if (s.Sfunc.Fflags & Fnodebug)
760             continue;
761         if (s.Sfunc.Fflags & Fintro)
762             mlen += 4;
763         mlen += cgcv.sz_idx * 2;
764         count++;
765     }
766 
767     if (!count)
768         return 0;
769 
770     // Allocate and fill it in
771     d = debtyp_alloc(mlen);
772     p = d.data.ptr;
773     TOWORD(p,LF_METHODLIST);
774     p += 2;
775     for (s = sf; s; s = s.Sfunc.Foversym)
776     {
777         if (s.Sclass == SC.typedef_ || s.Sclass == SC.functempl)
778             continue;
779         if (s.Sfunc.Fflags & Fnodebug)
780             continue;
781         attribute = cast(ushort)SFLtoATTR(s.Sflags);
782         // Make sure no overlapping bits
783         assert((Fvirtual | Fpure | Fintro | Fstatic) == (Fvirtual ^ Fpure ^ Fintro ^ Fstatic));
784         switch ((s.Sfunc.Fflags & (Fvirtual | Fstatic)) |
785                 (s.Sfunc.Fflags & (Fpure | Fintro)))
786         {
787             // BUG: should we have 0x0C, friend functions?
788             case Fstatic:                       attribute |= 0x08; break;
789             case Fvirtual:                      attribute |= 0x04; break;
790             case Fvirtual | Fintro:             attribute |= 0x10; break;
791             case Fvirtual | Fpure:              attribute |= 0x14; break;
792             case Fvirtual | Fintro | Fpure:     attribute |= 0x18; break;
793 
794             case 0:
795                 break;
796 
797             default:
798                 symbol_print(s);
799                 assert(0);
800         }
801         TOIDX(p,attribute);
802         p += cgcv.sz_idx;
803         TOIDX(p,cv4_symtypidx(s));
804         p += cgcv.sz_idx;
805         if (s.Sfunc.Fflags & Fintro)
806         {   TOLONG(p,cpp_vtbloffset(cast(Classsym *)s.Sscope,s));
807             p += 4;
808         }
809     }
810     assert(p - d.data.ptr == mlen);
811 
812     *pcount = count;
813     return cv_debtyp(d);
814 }
815 
816 }
817 
818 /**********************************
819  * Pretty-print indentifier for CV4 types.
820  */
821 
822 version (SCPP)
823 {
824 
825 private const(char)* cv4_prettyident(Symbol *s)
826 {   Symbol *stmp;
827 
828     stmp = s.Sscope;
829     s.Sscope = null;           // trick cpp_prettyident into leaving off ::
830     const p = cpp_prettyident(s);
831     s.Sscope = cast(Classsym *)stmp;
832     return p;
833 }
834 
835 }
836 
837 /****************************
838  * Return type index of struct.
839  * Input:
840  *      s       struct tag symbol
841  *      flags
842  *          0   generate a reference to s
843  *          1   just saw the definition of s
844  *          2   saw key function for class s
845  *          3   no longer have a key function for class s
846  */
847 
848 @trusted
849 idx_t cv4_struct(Classsym *s,int flags)
850 {   targ_size_t size;
851     debtyp_t* d,dt;
852     uint len;
853     uint nfields,fnamelen;
854     idx_t typidx;
855     type *t;
856     struct_t *st;
857     const(char)* id;
858 version (SCPP)
859 {
860     baseclass_t *b;
861 }
862     uint numidx;
863     uint leaf;
864     uint property;
865     uint attribute;
866     ubyte *p;
867     int refonly;
868     int i;
869     int count;                  // COUNT field in LF_CLASS
870 
871     symbol_debug(s);
872     assert(config.fulltypes >= CV4);
873     st = s.Sstruct;
874     if (st.Sflags & STRanonymous)      // if anonymous class/union
875         return 0;
876 
877     //printf("cv4_struct(%s,%d)\n",s.Sident.ptr,flags);
878     t = s.Stype;
879     //printf("t = %p, Tflags = x%x\n", t, t.Tflags);
880     type_debug(t);
881 
882     // Determine if we should do a reference or a definition
883     refonly = 1;                        // assume reference only
884     if (MARS || t.Tflags & TFsizeunknown || st.Sflags & STRoutdef)
885     {
886         //printf("ref only\n");
887     }
888     else
889     {
890         // We have a definition that we have not put out yet
891         switch (flags)
892         {
893             case 0:                     // reference to s
894 version (SCPP)
895 {
896                 if (!CPP ||
897                     config.flags2 & (CFG2fulltypes | CFG2hdrdebug) ||
898                     !(st.Sflags & STRvtblext))
899                     refonly = 0;
900 }
901 else
902 {
903                 refonly = 0;
904 }
905                 break;
906 
907             case 1:                     // saw def of s
908                 if (!s.Stypidx)        // if not forward referenced
909                     return 0;
910 version (SCPP)
911 {
912                 if (!CPP ||
913                     config.flags2 & CFG2fulltypes ||
914                     !(st.Sflags & STRvtblext))
915                     refonly = 0;
916 }
917                 break;
918 
919 version (SCPP)
920 {
921             case 2:                     // saw key func for s
922                 if (config.flags2 & CFG2fulltypes)
923                     return 0;
924                 refonly = 0;
925                 break;
926 
927             case 3:                     // no longer have key func for s
928                 if (!s.Stypidx || config.flags2 & CFG2fulltypes)
929                     return 0;
930                 refonly = 0;
931                 break;
932 }
933             default:
934                 assert(0);
935         }
936     }
937 
938     if (MARS || refonly)
939     {
940         if (s.Stypidx)                 // if reference already generated
941         {   //assert(s.Stypidx - cgcv.deb_offset < debtyp.length);
942             return s.Stypidx;          // use already existing reference
943         }
944         size = 0;
945         property = 0x80;                // class is forward referenced
946     }
947     else
948     {   size = type_size(t);
949         st.Sflags |= STRoutdef;
950         property = 0;
951     }
952 
953 version (SCPP)
954 {
955     if (CPP)
956     {
957         if (s.Sscope)                  // if class is nested
958             property |= 8;
959         if (st.Sctor || st.Sdtor)
960             property |= 2;              // class has ctors and/or dtors
961         if (st.Sopoverload)
962             property |= 4;              // class has overloaded operators
963         if (st.Scastoverload)
964             property |= 0x40;           // class has casting methods
965         if (st.Sopeq && !(st.Sopeq.Sfunc.Fflags & Fnodebug))
966             property |= 0x20;           // class has overloaded assignment
967     }
968 }
969     id = prettyident(s);
970     if (config.fulltypes == CV4)
971     {   numidx = (st.Sflags & STRunion) ? 8 : 12;
972         len = numidx + cv4_numericbytes(cast(uint)size);
973         d = debtyp_alloc(len + cv_stringbytes(id));
974         cv4_storenumeric(d.data.ptr + numidx,cast(uint)size);
975     }
976     else
977     {   numidx = (st.Sflags & STRunion) ? 10 : 18;
978         len = numidx + 4;
979         d = debtyp_alloc(len + cv_stringbytes(id));
980         TOLONG(d.data.ptr + numidx,cast(uint)size);
981     }
982     len += cv_namestring(d.data.ptr + len,id);
983     switch (s.Sclass)
984     {
985         case SC.struct_:
986             leaf = LF_STRUCTURE;
987             if (st.Sflags & STRunion)
988             {   leaf = LF_UNION;
989                 break;
990             }
991             if (st.Sflags & STRclass)
992                 leaf = LF_CLASS;
993             goto L1;
994         L1:
995             if (config.fulltypes == CV4)
996                 TOWORD(d.data.ptr + 8,0);          // dList
997             else
998                 TOLONG(d.data.ptr + 10,0);         // dList
999         if (CPP)
1000         {
1001 version (SCPP)
1002 {
1003             debtyp_t *vshape;
1004             ubyte descriptor;
1005 
1006             const n = list_nitems(st.Svirtual);
1007             if (n == 0)                         // if no virtual functions
1008             {
1009                 if (config.fulltypes == CV4)
1010                     TOWORD(d.data.ptr + 10,0);             // vshape is 0
1011                 else
1012                     TOLONG(d.data.ptr + 14,0);             // vshape is 0
1013             }
1014             else
1015             {
1016                 vshape = debtyp_alloc(4 + (n + 1) / 2);
1017                 TOWORD(vshape.data.ptr,LF_VTSHAPE);
1018                 TOWORD(vshape.data.ptr + 2,1);
1019 
1020                 uint n2 = 0;
1021                 descriptor = 0;
1022                 foreach (vl; ListRange(st.Svirtual))
1023                 {   mptr_t *m;
1024                     tym_t ty;
1025 
1026                     m = list_mptr(vl);
1027                     symbol_debug(m.MPf);
1028                     ty = tybasic(m.MPf.ty());
1029                     assert(tyfunc(ty));
1030                     if (_tysize[TYint] == 4)
1031                         descriptor |= 5;
1032                     if (tyfarfunc(ty))
1033                         descriptor++;
1034                     vshape.data.ptr[4 + n2 / 2] = descriptor;
1035                     descriptor <<= 4;
1036                     n2++;
1037                 }
1038                 if (config.fulltypes == CV4)
1039                     TOWORD(d.data.ptr + 10,cv_debtyp(vshape));     // vshape
1040                 else
1041                     TOLONG(d.data.ptr + 14,cv_debtyp(vshape));     // vshape
1042             }
1043 }
1044         }
1045         else
1046         {
1047             if (config.fulltypes == CV4)
1048                 TOWORD(d.data.ptr + 10,0);         // vshape
1049             else
1050                 TOLONG(d.data.ptr + 14,0);         // vshape
1051         }
1052             break;
1053 
1054         default:
1055             symbol_print(s);
1056             assert(0);
1057     }
1058     TOWORD(d.data.ptr,leaf);
1059 
1060     // Assign a number to prevent infinite recursion if a struct member
1061     // references the same struct.
1062     if (config.fulltypes == CVTDB)
1063     {
1064     }
1065     else
1066     {
1067         d.length = 0;                  // so cv_debtyp() will allocate new
1068         s.Stypidx = cv_debtyp(d);
1069         d.length = cast(ushort)len;    // restore length
1070     }
1071     reset_symbuf.write((&s)[0 .. 1]);
1072 
1073     if (refonly)                        // if reference only
1074     {
1075         //printf("refonly\n");
1076         TOWORD(d.data.ptr + 2,0);          // count: number of fields is 0
1077         if (config.fulltypes == CV4)
1078         {   TOWORD(d.data.ptr + 4,0);              // field list is 0
1079             TOWORD(d.data.ptr + 6,property);
1080         }
1081         else
1082         {   TOLONG(d.data.ptr + 6,0);              // field list is 0
1083             TOWORD(d.data.ptr + 4,property);
1084         }
1085         return s.Stypidx;
1086     }
1087 
1088 version (MARS)
1089     util_progress();
1090 else
1091     file_progress();
1092 
1093     // Compute the number of fields, and the length of the fieldlist record
1094     nfields = 0;
1095     fnamelen = 2;
1096 version (SCPP)
1097 {
1098     if (CPP)
1099     {
1100     // Base classes come first
1101     for (b = st.Sbase; b; b = b.BCnext)
1102     {
1103         if (b.BCflags & BCFvirtual)    // skip virtual base classes
1104             continue;
1105         nfields++;
1106         fnamelen += ((config.fulltypes == CV4) ? 6 : 8) +
1107                     cv4_numericbytes(b.BCoffset);
1108     }
1109 
1110     // Now virtual base classes (direct and indirect)
1111     for (b = st.Svirtbase; b; b = b.BCnext)
1112     {
1113         nfields++;
1114         fnamelen += ((config.fulltypes == CV4) ? 8 : 12) +
1115                         cv4_numericbytes(st.Svbptr_off) +
1116                         cv4_numericbytes(b.BCvbtbloff / _tysize[TYint]);
1117     }
1118 
1119     // Now friend classes
1120     i = list_nitems(st.Sfriendclass);
1121     nfields += i;
1122     fnamelen += i * ((config.fulltypes == CV4) ? 4 : 8);
1123 
1124     // Now friend functions
1125     foreach (sl; ListRange(st.Sfriendfuncs))
1126     {   Symbol *sf = list_symbol(sl);
1127 
1128         symbol_debug(sf);
1129         if (sf.Sclass == SC.functempl)
1130             continue;
1131         nfields++;
1132         fnamelen += ((config.fulltypes == CV4) ? 4 : 6) +
1133                     cv_stringbytes(cpp_unmangleident(sf.Sident.ptr));
1134     }
1135     }
1136 }
1137     count = nfields;
1138     foreach (sl; ListRange(st.Sfldlst))
1139     {   Symbol *sf = list_symbol(sl);
1140         targ_size_t offset;
1141 
1142         symbol_debug(sf);
1143         const(char)* sfid = sf.Sident.ptr;
1144         switch (sf.Sclass)
1145         {
1146             case SC.member:
1147             case SC.field:
1148                 if (CPP && sf == s.Sstruct.Svptr)
1149                     fnamelen += ((config.fulltypes == CV4) ? 4 : 8);
1150                 else
1151                 {   offset = sf.Smemoff;
1152                     fnamelen += ((config.fulltypes == CV4) ? 6 : 8) +
1153                                 cv4_numericbytes(cast(uint)offset) + cv_stringbytes(sfid);
1154                 }
1155                 break;
1156 
1157 version (SCPP)
1158 {
1159             case SC.struct_:
1160                 if (sf.Sstruct.Sflags & STRanonymous)
1161                     continue;
1162                 if (sf.Sstruct.Sflags & STRnotagname)
1163                     sfid = cpp_name_none.ptr;
1164                 property |= 0x10;       // class contains nested classes
1165                 goto Lnest2;
1166 
1167             case SC.enum_:
1168                 if (sf.Senum.SEflags & SENnotagname)
1169                     sfid = cpp_name_none.ptr;
1170                 goto Lnest2;
1171 
1172             case SC.typedef_:
1173             Lnest2:
1174                 fnamelen += ((config.fulltypes == CV4) ? 4 : 8) +
1175                             cv_stringbytes(sfid);
1176                 break;
1177 
1178             case SC.extern_:
1179             case SC.comdef:
1180             case SC.global:
1181             case SC.static_:
1182             case SC.inline:
1183             case SC.sinline:
1184             case SC.einline:
1185             case SC.comdat:
1186                 if (tyfunc(sf.ty()))
1187                 {   Symbol *so;
1188                     int nfuncs;
1189 
1190                     nfuncs = 0;
1191                     for (so = sf; so; so = so.Sfunc.Foversym)
1192                     {
1193                         if (so.Sclass == SC.typedef_ ||
1194                             so.Sclass == SC.functempl ||
1195                             so.Sfunc.Fflags & Fnodebug)       // if compiler generated
1196                             continue;                   // skip it
1197                         nfuncs++;
1198                     }
1199                     if (nfuncs == 0)
1200                         continue;
1201 
1202                     if (nfuncs > 1)
1203                         count += nfuncs - 1;
1204 
1205                     sfid = cv4_prettyident(sf);
1206                 }
1207                 fnamelen += ((config.fulltypes == CV4) ? 6 : 8) +
1208                             cv_stringbytes(sfid);
1209                 break;
1210 }
1211 
1212             default:
1213                 continue;
1214         }
1215         nfields++;
1216         count++;
1217     }
1218 
1219     TOWORD(d.data.ptr + 2,count);
1220     if (config.fulltypes == CV4)
1221         TOWORD(d.data.ptr + 6,property);
1222     else
1223         TOWORD(d.data.ptr + 4,property);
1224 
1225     // Generate fieldlist type record
1226     dt = debtyp_alloc(fnamelen);
1227     p = dt.data.ptr;
1228     TOWORD(p,LF_FIELDLIST);
1229 
1230     // And fill it in
1231     p += 2;
1232 version (SCPP)
1233 {
1234     if (CPP)
1235     {
1236     // Put out real base classes
1237     for (b = st.Sbase; b; b = b.BCnext)
1238     {   targ_size_t offset;
1239 
1240         if (b.BCflags & BCFvirtual)    // skip virtual base classes
1241             continue;
1242         offset = b.BCoffset;
1243         typidx = cv4_symtypidx(b.BCbase);
1244 
1245         attribute = (b.BCflags & BCFpmask);
1246         if (attribute & 4)
1247             attribute = 1;
1248         else
1249             attribute = 4 - attribute;
1250 
1251         TOWORD(p,LF_BCLASS);
1252         if (config.fulltypes == CV4)
1253         {   TOWORD(p + 2,typidx);
1254             TOWORD(p + 4,attribute);
1255             p += 6;
1256         }
1257         else
1258         {   TOLONG(p + 4,typidx);
1259             TOWORD(p + 2,attribute);
1260             p += 8;
1261         }
1262 
1263         cv4_storenumeric(p,offset);
1264         p += cv4_numericbytes(offset);
1265     }
1266 
1267     // Now direct followed by indirect virtual base classes
1268     i = LF_VBCLASS;
1269     do
1270     {
1271         for (b = st.Svirtbase; b; b = b.BCnext)
1272         {   targ_size_t vbpoff,vboff;
1273             type *vbptype;              // type of virtual base pointer
1274             idx_t vbpidx;
1275 
1276             if (baseclass_find(st.Sbase,b.BCbase))    // if direct vbase
1277             {   if (i == LF_IVBCLASS)
1278                     continue;
1279             }
1280             else
1281             {   if (i == LF_VBCLASS)
1282                     continue;
1283             }
1284 
1285             typidx = cv4_symtypidx(b.BCbase);
1286 
1287             vbptype = type_allocn(TYarray,tstypes[TYint]);
1288             vbptype.Tflags |= TFsizeunknown;
1289             vbptype = newpointer(vbptype);
1290             vbptype.Tcount++;
1291             vbpidx = cv4_typidx(vbptype);
1292             type_free(vbptype);
1293 
1294             attribute = (b.BCflags & BCFpmask);
1295             if (attribute & 4)
1296                 attribute = 1;
1297             else
1298                 attribute = 4 - attribute;
1299 
1300             vbpoff = st.Svbptr_off;
1301             vboff = b.BCvbtbloff / _tysize[TYint];
1302 
1303             if (config.fulltypes == CV4)
1304             {   TOWORD(p,i);
1305                 TOWORD(p + 2,typidx);
1306                 TOWORD(p + 4,vbpidx);
1307                 TOWORD(p + 6,attribute);
1308                 p += 8;
1309             }
1310             else
1311             {   TOWORD(p,i);
1312                 TOLONG(p + 4,typidx);           // btype
1313                 TOLONG(p + 8,vbpidx);           // vbtype
1314                 TOWORD(p + 2,attribute);
1315                 p += 12;
1316             }
1317 
1318             cv4_storenumeric(p,vbpoff);
1319             p += cv4_numericbytes(vbpoff);
1320             cv4_storenumeric(p,vboff);
1321             p += cv4_numericbytes(vboff);
1322         }
1323         i ^= LF_VBCLASS ^ LF_IVBCLASS;          // toggle between them
1324     } while (i != LF_VBCLASS);
1325 
1326     // Now friend classes
1327     foreach (sl; ListRange(s.Sstruct.Sfriendclass))
1328     {   Symbol *sf = list_symbol(sl);
1329 
1330         symbol_debug(sf);
1331         typidx = cv4_symtypidx(sf);
1332         if (config.fulltypes == CV4)
1333         {   TOWORD(p,LF_FRIENDCLS);
1334             TOWORD(p + 2,typidx);
1335             p += 4;
1336         }
1337         else
1338         {   TOLONG(p,LF_FRIENDCLS);
1339             TOLONG(p + 4,typidx);
1340             p += 8;
1341         }
1342     }
1343 
1344     // Now friend functions
1345     foreach (sl; ListRange(s.Sstruct.Sfriendfuncs))
1346     {   Symbol *sf = list_symbol(sl);
1347 
1348         symbol_debug(sf);
1349         if (sf.Sclass == SC.functempl)
1350             continue;
1351         typidx = cv4_symtypidx(sf);
1352         TOWORD(p,LF_FRIENDFCN);
1353         if (config.fulltypes == CV4)
1354         {   TOWORD(p + 2,typidx);
1355             p += 4;
1356         }
1357         else
1358         {   TOLONG(p + 2,typidx);
1359             p += 6;
1360         }
1361         p += cv_namestring(p,cpp_unmangleident(sf.Sident.ptr));
1362     }
1363     }
1364 }
1365     foreach (sl; ListRange(s.Sstruct.Sfldlst))
1366     {   Symbol *sf = list_symbol(sl);
1367         targ_size_t offset;
1368 
1369         symbol_debug(sf);
1370         const(char)* sfid = sf.Sident.ptr;
1371         switch (sf.Sclass)
1372         {
1373             case SC.field:
1374             {   debtyp_t *db;
1375 
1376                 if (config.fulltypes == CV4)
1377                 {   db = debtyp_alloc(6);
1378                     TOWORD(db.data.ptr,LF_BITFIELD);
1379                     db.data.ptr[2] = sf.Swidth;
1380                     db.data.ptr[3] = sf.Sbit;
1381                     TOWORD(db.data.ptr + 4,cv4_symtypidx(sf));
1382                 }
1383                 else
1384                 {   db = debtyp_alloc(8);
1385                     TOWORD(db.data.ptr,LF_BITFIELD);
1386                     db.data.ptr[6] = sf.Swidth;
1387                     db.data.ptr[7] = sf.Sbit;
1388                     TOLONG(db.data.ptr + 2,cv4_symtypidx(sf));
1389                 }
1390                 typidx = cv_debtyp(db);
1391                 goto L3;
1392             }
1393 
1394             case SC.member:
1395                 typidx = cv4_symtypidx(sf);
1396             L3:
1397 version (SCPP)
1398 {
1399                 if (CPP && sf == s.Sstruct.Svptr)
1400                 {
1401                     if (config.fulltypes == CV4)
1402                     {   TOWORD(p,LF_VFUNCTAB);
1403                         TOWORD(p + 2,typidx);
1404                         p += 4;
1405                     }
1406                     else
1407                     {   TOLONG(p,LF_VFUNCTAB);          // 0 fill 2 bytes
1408                         TOLONG(p + 4,typidx);
1409                         p += 8;
1410                     }
1411                     break;
1412                 }
1413 }
1414                 offset = sf.Smemoff;
1415                 TOWORD(p,LF_MEMBER);
1416 version (SCPP)
1417 {
1418                 attribute = CPP ? SFLtoATTR(sf.Sflags) : 0;
1419                 assert((attribute & ~3) == 0);
1420 }
1421 else
1422 {
1423                 attribute = 0;
1424 }
1425                 if (config.fulltypes == CV4)
1426                 {   TOWORD(p + 2,typidx);
1427                     TOWORD(p + 4,attribute);
1428                     p += 6;
1429                 }
1430                 else
1431                 {   TOLONG(p + 4,typidx);
1432                     TOWORD(p + 2,attribute);
1433                     p += 8;
1434                 }
1435                 cv4_storenumeric(p,cast(uint)offset);
1436                 p += cv4_numericbytes(cast(uint)offset);
1437                 p += cv_namestring(p,sfid);
1438                 break;
1439 
1440 version (SCPP)
1441 {
1442             case SC.struct_:
1443                 if (sf.Sstruct.Sflags & STRanonymous)
1444                     continue;
1445                 if (sf.Sstruct.Sflags & STRnotagname)
1446                     sfid = cpp_name_none.ptr;
1447                 goto Lnest;
1448 
1449             case SC.enum_:
1450                 if (sf.Senum.SEflags & SENnotagname)
1451                     sfid = cpp_name_none.ptr;
1452                 goto Lnest;
1453 
1454             case SC.typedef_:
1455             Lnest:
1456                 TOWORD(p,LF_NESTTYPE);
1457                 typidx = cv4_symtypidx(sf);
1458                 if (config.fulltypes == CV4)
1459                 {   TOWORD(p + 2,typidx);
1460                     p += 4;
1461                 }
1462                 else
1463                 {   TOLONG(p + 4,typidx);
1464                     p += 8;
1465                 }
1466             L2:
1467                 p += cv_namestring(p,sfid);
1468                 break;
1469 
1470             case SC.extern_:
1471             case SC.comdef:
1472             case SC.global:
1473             case SC.static_:
1474             case SC.inline:
1475             case SC.sinline:
1476             case SC.einline:
1477             case SC.comdat:
1478                 if (tyfunc(sf.ty()))
1479                 {   int count2;
1480 
1481                     typidx = cv4_methodlist(sf,&count2);
1482                     if (!typidx)
1483                         break;
1484                     sfid = cv4_prettyident(sf);
1485                     TOWORD(p,LF_METHOD);
1486                     TOWORD(p + 2,count2);
1487                     p += 4;
1488                     TOIDX(p,typidx);
1489                     p += cgcv.sz_idx;
1490                     goto L2;
1491                 }
1492                 else
1493                 {
1494                     TOWORD(p,LF_STMEMBER);
1495                     typidx = cv4_symtypidx(sf);
1496                     attribute = SFLtoATTR(sf.Sflags);
1497                     if (config.fulltypes == CV4)
1498                     {   TOWORD(p + 2,typidx);
1499                         TOWORD(p + 4,attribute);
1500                         p += 6;
1501                     }
1502                     else
1503                     {   TOLONG(p + 4,typidx);
1504                         TOWORD(p + 2,attribute);
1505                         p += 8;
1506                     }
1507                     goto L2;
1508                 }
1509                 break;
1510 }
1511 
1512             default:
1513                 continue;
1514         }
1515     }
1516     //printf("fnamelen = %d, p-dt.data = %d\n",fnamelen,p-dt.data);
1517     assert(p - dt.data.ptr == fnamelen);
1518     if (config.fulltypes == CV4)
1519         TOWORD(d.data.ptr + 4,cv_debtyp(dt));
1520     else
1521         TOLONG(d.data.ptr + 6,cv_debtyp(dt));
1522 
1523 version (SCPP)
1524 {
1525     if (CPP)
1526     {
1527         symbol_debug(s);
1528         if (st.Sflags & STRglobal)
1529             list_prepend(&cgcv.list,s);
1530         else
1531             cv4_outsym(s);
1532     }
1533 }
1534     return s.Stypidx;
1535 }
1536 
1537 /****************************
1538  * Return type index of enum.
1539  */
1540 
1541 version (SCPP)
1542 {
1543 @trusted
1544 private uint cv4_enum(Symbol *s)
1545 {
1546     debtyp_t* d,dt;
1547     uint nfields,fnamelen;
1548     uint len;
1549     type *t;
1550     type *tbase;
1551     uint property;
1552     uint attribute;
1553     int i;
1554     char *id;
1555 
1556     symbol_debug(s);
1557     if (s.Stypidx)                     // if already converted
1558     {   //assert(s.Stypidx - cgcv.deb_offset < debtyp.length);
1559         return s.Stypidx;
1560     }
1561 
1562     //printf("cv4_enum(%s)\n",s.Sident.ptr);
1563     t = s.Stype;
1564     type_debug(t);
1565     tbase = t.Tnext;
1566     property = 0;
1567     if (s.Senum.SEflags & SENforward)
1568         property |= 0x80;               // enum is forward referenced
1569 
1570     id = s.Sident.ptr;
1571     if (s.Senum.SEflags & SENnotagname)
1572         id = cpp_name_none.ptr;
1573     if (config.fulltypes == CV4)
1574     {   len = 10;
1575         d = debtyp_alloc(len + cv_stringbytes(id));
1576         TOWORD(d.data.ptr,LF_ENUM);
1577         TOWORD(d.data.ptr + 4,cv4_typidx(tbase));
1578         TOWORD(d.data.ptr + 8,property);
1579     }
1580     else
1581     {   len = 14;
1582         d = debtyp_alloc(len + cv_stringbytes(id));
1583         TOWORD(d.data.ptr,LF_ENUM);
1584         TOLONG(d.data.ptr + 6,cv4_typidx(tbase));
1585         TOWORD(d.data.ptr + 4,property);
1586     }
1587     len += cv_namestring(d.data.ptr + len,id);
1588 
1589     // Assign a number to prevent infinite recursion if an enum member
1590     // references the same enum.
1591     if (config.fulltypes == CVTDB)
1592     {
1593 static if (SYMDEB_TDB)
1594 {
1595         debtyp_t *df;
1596 
1597         TOWORD(d.data.ptr + 2,0);
1598         TOWORD(d.data.ptr + 6,0);
1599         debtyp_check(d);
1600         s.Stypidx = tdb_typidx(&d.length);    // forward reference it
1601 }
1602     }
1603     else
1604     {
1605         d.length = 0;                  // so cv_debtyp() will allocate new
1606         s.Stypidx = cv_debtyp(d);
1607         d.length = cast(ushort)len;           // restore length
1608     }
1609     reset_symbuf.write((&s)[0 .. 1]);
1610 
1611     // Compute the number of fields, and the length of the fieldlist record
1612     nfields = 0;
1613     fnamelen = 2;
1614     foreach (sl; ListRange(s.Senum.SEenumlist))
1615     {   Symbol *sf = list_symbol(sl);
1616         uint value;
1617 
1618         symbol_debug(sf);
1619         value = cast(uint)el_tolongt(sf.Svalue);
1620         nfields++;
1621         fnamelen += 4 + cv4_numericbytes(value) + cv_stringbytes(sf.Sident.ptr);
1622     }
1623 
1624     TOWORD(d.data.ptr + 2,nfields);
1625 
1626     // If forward reference, then field list is 0
1627     if (s.Senum.SEflags & SENforward)
1628     {
1629         TOWORD(d.data.ptr + 6,0);
1630         return s.Stypidx;
1631     }
1632 
1633     // Generate fieldlist type record
1634     dt = debtyp_alloc(fnamelen);
1635     TOWORD(dt.data.ptr,LF_FIELDLIST);
1636 
1637     // And fill it in
1638     i = 2;
1639     foreach (sl; ListRange(s.Senum.SEenumlist))
1640     {   Symbol *sf = list_symbol(sl);
1641         uint value;
1642 
1643         symbol_debug(sf);
1644         value = cast(uint)el_tolongt(sf.Svalue);
1645         TOWORD(dt.data.ptr + i,LF_ENUMERATE);
1646         attribute = SFLtoATTR(sf.Sflags);
1647         TOWORD(dt.data.ptr + i + 2,attribute);
1648         cv4_storenumeric(dt.data.ptr + i + 4,value);
1649         i += 4 + cv4_numericbytes(value);
1650         i += cv_namestring(dt.data.ptr + i,sf.Sident.ptr);
1651 
1652         // If enum is not a member of a class, output enum members as constants
1653         if (!isclassmember(s))
1654         {   symbol_debug(sf);
1655             cv4_outsym(sf);
1656         }
1657     }
1658     assert(i == fnamelen);
1659     if (config.fulltypes == CV4)
1660         TOWORD(d.data.ptr + 6,cv_debtyp(dt));
1661     else
1662         TOLONG(d.data.ptr + 10,cv_debtyp(dt));
1663 
1664     symbol_debug(s);
1665     if (CPP)
1666         cv4_outsym(s);
1667     return s.Stypidx;
1668 }
1669 
1670 }
1671 else
1672 {
1673 @trusted
1674 private uint cv4_fwdenum(type* t)
1675 {
1676     Symbol* s = t.Ttag;
1677 
1678     // write a forward reference enum record that is enough for the linker to
1679     // fold with original definition from EnumDeclaration
1680     uint bty = dttab4[tybasic(t.Tnext.Tty)];
1681     const id = prettyident(s);
1682     uint len = config.fulltypes == CV8 ? 14 : 10;
1683     debtyp_t* d = debtyp_alloc(len + cv_stringbytes(id));
1684     switch (config.fulltypes)
1685     {
1686         case CV8:
1687             TOWORD(d.data.ptr, LF_ENUM_V3);
1688             TOLONG(d.data.ptr + 2, 0);    // count
1689             TOWORD(d.data.ptr + 4, 0x80); // property : forward reference
1690             TOLONG(d.data.ptr + 6, bty);  // memtype
1691             TOLONG(d.data.ptr + 10, 0);   // fieldlist
1692             break;
1693 
1694         case CV4:
1695             TOWORD(d.data.ptr,LF_ENUM);
1696             TOWORD(d.data.ptr + 2, 0);    // count
1697             TOWORD(d.data.ptr + 4, bty);  // memtype
1698             TOLONG(d.data.ptr + 6, 0);    // fieldlist
1699             TOWORD(d.data.ptr + 8, 0x80); // property : forward reference
1700             break;
1701 
1702         default:
1703             assert(0);
1704     }
1705     cv_namestring(d.data.ptr + len, id);
1706     s.Stypidx = cv_debtyp(d);
1707     return s.Stypidx;
1708 }
1709 
1710 }
1711 /************************************************
1712  * Return 'calling convention' type of function.
1713  */
1714 
1715 ubyte cv4_callconv(type *t)
1716 {   ubyte call;
1717 
1718     switch (tybasic(t.Tty))
1719     {
1720         case TYffunc:   call = 1;       break;
1721         case TYfpfunc:  call = 3;       break;
1722         case TYf16func: call = 3;       break;
1723         case TYfsfunc:  call = 8;       break;
1724         case TYnsysfunc: call = 9;      break;
1725         case TYfsysfunc: call = 10;     break;
1726         case TYnfunc:   call = 0;       break;
1727         case TYnpfunc:  call = 2;       break;
1728         case TYnsfunc:  call = 7;       break;
1729         case TYifunc:   call = 1;       break;
1730         case TYjfunc:   call = 2;       break;
1731         case TYmfunc:   call = 11;      break;  // this call
1732         default:
1733             assert(0);
1734     }
1735     return call;
1736 }
1737 
1738 /**********************************************
1739  * Return type index for the type of a symbol.
1740  */
1741 
1742 version (MARS)
1743 {
1744 
1745 private uint cv4_symtypidx(Symbol *s)
1746 {
1747     return cv4_typidx(s.Stype);
1748 }
1749 
1750 }
1751 
1752 version (SCPP)
1753 {
1754 
1755 @trusted
1756 private uint cv4_symtypidx(Symbol *s)
1757 {   type *t;
1758     debtyp_t *d;
1759     ubyte *p;
1760 
1761     if (!CPP)
1762         return cv4_typidx(s.Stype);
1763     symbol_debug(s);
1764     if (isclassmember(s))
1765     {   t = s.Stype;
1766         if (tyfunc(t.Tty))
1767         {   param_t *pa;
1768             uint nparam;
1769             idx_t paramidx;
1770             idx_t thisidx;
1771             uint u;
1772             func_t *f;
1773             ubyte call;
1774 
1775             // It's a member function, which gets a special type record
1776 
1777             f = s.Sfunc;
1778             if (f.Fflags & Fstatic)
1779                 thisidx = dttab4[TYvoid];
1780             else
1781             {   type *tthis = cpp_thistype(s.Stype,cast(Classsym *)s.Sscope);
1782 
1783                 thisidx = cv4_typidx(tthis);
1784                 type_free(tthis);
1785             }
1786 
1787             paramidx = cv4_arglist(t,&nparam);
1788             call = cv4_callconv(t);
1789 
1790             if (config.fulltypes == CV4)
1791             {
1792                 d = debtyp_alloc(18);
1793                 p = d.data.ptr;
1794                 TOWORD(p,LF_MFUNCTION);
1795                 TOWORD(p + 2,cv4_typidx(t.Tnext));
1796                 TOWORD(p + 4,cv4_symtypidx(s.Sscope));
1797                 TOWORD(p + 6,thisidx);
1798                 p[8] = call;
1799                 p[9] = 0;                               // reserved
1800                 TOWORD(p + 10,nparam);
1801                 TOWORD(p + 12,paramidx);
1802                 TOLONG(p + 14,0);                       // thisadjust
1803             }
1804             else
1805             {
1806                 d = debtyp_alloc(26);
1807                 p = d.data.ptr;
1808                 TOWORD(p,LF_MFUNCTION);
1809                 TOLONG(p + 2,cv4_typidx(t.Tnext));
1810                 TOLONG(p + 6,cv4_symtypidx(s.Sscope));
1811                 TOLONG(p + 10,thisidx);
1812                 p[14] = call;
1813                 p[15] = 0;                              // reserved
1814                 TOWORD(p + 16,nparam);
1815                 TOLONG(p + 18,paramidx);
1816                 TOLONG(p + 22,0);                       // thisadjust
1817             }
1818             return cv_debtyp(d);
1819         }
1820     }
1821     return cv4_typidx(s.Stype);
1822 }
1823 
1824 }
1825 
1826 /***********************************
1827  * Return CV4 type index for a type.
1828  */
1829 
1830 @trusted
1831 uint cv4_typidx(type *t)
1832 {   uint typidx;
1833     uint u;
1834     uint next;
1835     uint key;
1836     debtyp_t *d;
1837     targ_size_t size;
1838     tym_t tym;
1839     tym_t tycv;
1840     tym_t tymnext;
1841     type *tv;
1842     uint dt;
1843     uint attribute;
1844     ubyte call;
1845 
1846     //printf("cv4_typidx(%p)\n",t);
1847     if (!t)
1848         return dttab4[TYint];           // assume int
1849     type_debug(t);
1850     next = cv4_typidx(t.Tnext);
1851     tycv = t.Tty;
1852     tym = tybasic(tycv);
1853     tycv &= mTYconst | mTYvolatile | mTYimmutable;
1854     attribute = 0;
1855 L1:
1856     dt = dttab4[tym];
1857     switch (tym)
1858     {
1859         case TYllong:
1860             if (t.Tnext)
1861                 goto Ldelegate;
1862             assert(dt);
1863             typidx = dt;
1864             break;
1865 
1866         case TYullong:
1867             if (t.Tnext)
1868                 goto Ldarray;
1869             assert(dt);
1870             typidx = dt;
1871             break;
1872 
1873         case TYvoid:
1874         case TYnoreturn:
1875         case TYchar:
1876         case TYschar:
1877         case TYuchar:
1878         case TYchar16:
1879         case TYshort:
1880         case TYushort:
1881         case TYint:
1882         case TYuint:
1883         case TYulong:
1884         case TYlong:
1885         case TYfloat:
1886         case TYdouble:
1887         case TYdouble_alias:
1888         case TYldouble:
1889         case TYifloat:
1890         case TYidouble:
1891         case TYildouble:
1892         case TYcfloat:
1893         case TYcdouble:
1894         case TYcldouble:
1895         case TYbool:
1896         case TYwchar_t:
1897         case TYdchar:
1898             assert(dt);
1899             typidx = dt;
1900             break;
1901 
1902         case TYnptr:
1903         case TYimmutPtr:
1904         case TYsharePtr:
1905         case TYrestrictPtr:
1906 version (MARS)
1907 {
1908             if (t.Tkey)
1909                 goto Laarray;
1910 }
1911             goto Lptr;
1912         case TYsptr:
1913         case TYcptr:
1914         case TYfgPtr:
1915         Lptr:
1916                         attribute |= I32 ? 10 : 0;      goto L2;
1917 
1918         case TYfptr:
1919         case TYvptr:    attribute |= I32 ? 11 : 1;      goto L2;
1920         case TYhptr:    attribute |= 2; goto L2;
1921 
1922         L2:
1923             if (config.fulltypes == CV4)
1924             {
1925                 // This is a hack to duplicate bugs in VC, so that the VC
1926                 // debugger will work.
1927                 tymnext = t.Tnext ? t.Tnext.Tty : TYint;
1928                 if (tymnext & (mTYconst | mTYimmutable | mTYvolatile) &&
1929                     !tycv &&
1930                     tyarithmetic(tymnext) &&
1931                     !(attribute & 0xE0)
1932                    )
1933                 {
1934                     typidx = dt | dttab4[tybasic(tymnext)];
1935                     break;
1936                 }
1937             }
1938             if ((next & 0xFF00) == 0 && !(attribute & 0xE0))
1939                 typidx = next | dt;
1940             else
1941             {
1942                 if (tycv & (mTYconst | mTYimmutable))
1943                     attribute |= 0x400;
1944                 if (tycv & mTYvolatile)
1945                     attribute |= 0x200;
1946                 tycv = 0;
1947                 switch (config.fulltypes)
1948                 {
1949                     case CV4:
1950                         d = debtyp_alloc(6);
1951                         TOWORD(d.data.ptr,LF_POINTER);
1952                         TOWORD(d.data.ptr + 2,attribute);
1953                         TOWORD(d.data.ptr + 4,next);
1954                         break;
1955 
1956                     case CV8:
1957                         d = debtyp_alloc(10);
1958                         TOWORD(d.data.ptr,0x1002);
1959                         TOLONG(d.data.ptr + 2,next);
1960                         // see https://github.com/Microsoft/microsoft-pdb/blob/master/include/cvinfo.h#L1514
1961                         // add size and pointer type (PTR_64 or PTR_NEAR32)
1962                         attribute |= (I64 ? (8 << 13) | 0xC : (4 << 13) | 0xA);
1963                         // convert reference to r-value reference to remove & from type display in debugger
1964                         if (attribute & 0x20)
1965                             attribute |= 0x80;
1966                         TOLONG(d.data.ptr + 6,attribute);
1967                         break;
1968 
1969                     default:
1970                         d = debtyp_alloc(10);
1971                         TOWORD(d.data.ptr,LF_POINTER);
1972                         TOLONG(d.data.ptr + 2,attribute);
1973                         TOLONG(d.data.ptr + 6,next);
1974                         break;
1975                 }
1976                 typidx = cv_debtyp(d);
1977             }
1978             break;
1979 
1980         Ldarray:
1981             switch (config.fulltypes)
1982             {
1983 version (MARS)
1984 {
1985                 case CV8:
1986                 {
1987                     typidx = cv8_darray(t, next);
1988                     break;
1989                 }
1990 }
1991                 case CV4:
1992 static if (1)
1993 {
1994                     d = debtyp_alloc(12);
1995                     TOWORD(d.data.ptr, LF_OEM);
1996                     TOWORD(d.data.ptr + 2, OEM);
1997                     TOWORD(d.data.ptr + 4, 1);     // 1 = dynamic array
1998                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
1999                     TOWORD(d.data.ptr + 8, 0x12);  // index type, T_LONG
2000                     TOWORD(d.data.ptr + 10, next); // element type
2001 }
2002 else
2003 {
2004                     d = debtyp_alloc(6);
2005                     TOWORD(d.data.ptr,LF_DYN_ARRAY);
2006                     TOWORD(d.data.ptr + 2, 0x12);  // T_LONG
2007                     TOWORD(d.data.ptr + 4, next);
2008 }
2009                     typidx = cv_debtyp(d);
2010                     break;
2011 
2012                 default:
2013                     assert(0);
2014             }
2015 
2016             break;
2017 
2018         Laarray:
2019 version (MARS)
2020 {
2021             key = cv4_typidx(t.Tkey);
2022             switch (config.fulltypes)
2023             {
2024                 case CV8:
2025                     typidx = cv8_daarray(t, key, next);
2026                     break;
2027 
2028                 case CV4:
2029 static if (1)
2030 {
2031                     d = debtyp_alloc(12);
2032                     TOWORD(d.data.ptr, LF_OEM);
2033                     TOWORD(d.data.ptr + 2, OEM);
2034                     TOWORD(d.data.ptr + 4, 2);     // 2 = associative array
2035                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
2036                     TOWORD(d.data.ptr + 8, key);   // key type
2037                     TOWORD(d.data.ptr + 10, next); // element type
2038 }
2039 else
2040 {
2041                     d = debtyp_alloc(6);
2042                     TOWORD(d.data.ptr,LF_ASSOC_ARRAY);
2043                     TOWORD(d.data.ptr + 2, key);   // key type
2044                     TOWORD(d.data.ptr + 4, next);  // element type
2045 }
2046                     typidx = cv_debtyp(d);
2047                     break;
2048 
2049                 default:
2050                     assert(0);
2051             }
2052 }
2053             break;
2054 
2055         Ldelegate:
2056             switch (config.fulltypes)
2057             {
2058 version (MARS)
2059 {
2060                 case CV8:
2061                     typidx = cv8_ddelegate(t, next);
2062                     break;
2063 }
2064 
2065                 case CV4:
2066                     tv = type_fake(TYnptr);
2067                     tv.Tcount++;
2068                     key = cv4_typidx(tv);
2069                     type_free(tv);
2070 static if (1)
2071 {
2072                     d = debtyp_alloc(12);
2073                     TOWORD(d.data.ptr, LF_OEM);
2074                     TOWORD(d.data.ptr + 2, OEM);
2075                     TOWORD(d.data.ptr + 4, 3);     // 3 = delegate
2076                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
2077                     TOWORD(d.data.ptr + 8, key);   // type of 'this', which is void*
2078                     TOWORD(d.data.ptr + 10, next); // function type
2079 }
2080 else
2081 {
2082                     d = debtyp_alloc(6);
2083                     TOWORD(d.data.ptr,LF_DELEGATE);
2084                     TOWORD(d.data.ptr + 2, key);   // type of 'this', which is void*
2085                     TOWORD(d.data.ptr + 4, next);  // function type
2086 }
2087                     typidx = cv_debtyp(d);
2088                     break;
2089 
2090                 default:
2091                     assert(0);
2092             }
2093             break;
2094 
2095         case TYcent:
2096             if (t.Tnext)
2097                 goto Ldelegate;
2098             assert(dt);
2099             typidx = dt;
2100             break;
2101 
2102         case TYucent:
2103             if (t.Tnext)
2104                 goto Ldarray;
2105             assert(dt);
2106             typidx = dt;
2107             break;
2108 
2109         case TYarray:
2110         {   if (t.Tflags & TFsizeunknown)
2111                 size = 0;               // don't complain if don't know size
2112             else
2113                 size = type_size(t);
2114         Larray:
2115             u = cv4_numericbytes(cast(uint)size);
2116             uint idxtype = I32 ? 0x12 : 0x11;  // T_LONG : T_SHORT
2117             if (I64)
2118                 idxtype = 0x23;                    // T_UQUAD
2119             if(next == dttab4[TYvoid])    // do not encode void[n], this confuses the debugger
2120                 next = dttab4[TYuchar];   // use ubyte instead
2121             switch (config.fulltypes)
2122             {
2123                 case CV8:
2124                     d = debtyp_alloc(10 + u + 1);
2125                     TOWORD(d.data.ptr,0x1503);
2126                     TOLONG(d.data.ptr + 2,next);
2127                     TOLONG(d.data.ptr + 6,idxtype);
2128                     d.data.ptr[10 + u] = 0;             // no name
2129                     cv4_storenumeric(d.data.ptr + 10,cast(uint)size);
2130                     break;
2131 
2132                 case CV4:
2133                     d = debtyp_alloc(6 + u + 1);
2134                     TOWORD(d.data.ptr,LF_ARRAY);
2135                     TOWORD(d.data.ptr + 2,next);
2136                     TOWORD(d.data.ptr + 4,idxtype);
2137                     d.data.ptr[6 + u] = 0;             // no name
2138                     cv4_storenumeric(d.data.ptr + 6,cast(uint)size);
2139                     break;
2140 
2141                 default:
2142                     d = debtyp_alloc(10 + u + 1);
2143                     TOWORD(d.data.ptr,LF_ARRAY);
2144                     TOLONG(d.data.ptr + 2,next);
2145                     TOLONG(d.data.ptr + 6,idxtype);
2146                     d.data.ptr[10 + u] = 0;            // no name
2147                     cv4_storenumeric(d.data.ptr + 10,cast(uint)size);
2148                     break;
2149             }
2150             typidx = cv_debtyp(d);
2151             break;
2152         }
2153 
2154         case TYffunc:
2155         case TYfpfunc:
2156         case TYf16func:
2157         case TYfsfunc:
2158         case TYnsysfunc:
2159         case TYfsysfunc:
2160         case TYnfunc:
2161         case TYnpfunc:
2162         case TYnsfunc:
2163         case TYmfunc:
2164         case TYjfunc:
2165         case TYifunc:
2166         {
2167             param_t *p;
2168             uint nparam;
2169             idx_t paramidx;
2170 
2171             call = cv4_callconv(t);
2172             paramidx = cv4_arglist(t,&nparam);
2173 
2174             // Construct an LF_PROCEDURE
2175             switch (config.fulltypes)
2176             {
2177                 case CV8:
2178                     d = debtyp_alloc(2 + 4 + 1 + 1 + 2 + 4);
2179                     TOWORD(d.data.ptr,LF_PROCEDURE_V2);
2180                     TOLONG(d.data.ptr + 2,next);       // return type
2181                     d.data.ptr[6] = call;
2182                     d.data.ptr[7] = 0;                 // reserved
2183                     TOWORD(d.data.ptr + 8,nparam);
2184                     TOLONG(d.data.ptr + 10,paramidx);
2185                     break;
2186 
2187                 case CV4:
2188                     d = debtyp_alloc(2 + 2 + 1 + 1 + 2 + 2);
2189                     TOWORD(d.data.ptr,LF_PROCEDURE);
2190                     TOWORD(d.data.ptr + 2,next);               // return type
2191                     d.data.ptr[4] = call;
2192                     d.data.ptr[5] = 0;                 // reserved
2193                     TOWORD(d.data.ptr + 6,nparam);
2194                     TOWORD(d.data.ptr + 8,paramidx);
2195                     break;
2196 
2197                 default:
2198                     d = debtyp_alloc(2 + 4 + 1 + 1 + 2 + 4);
2199                     TOWORD(d.data.ptr,LF_PROCEDURE);
2200                     TOLONG(d.data.ptr + 2,next);               // return type
2201                     d.data.ptr[6] = call;
2202                     d.data.ptr[7] = 0;                 // reserved
2203                     TOWORD(d.data.ptr + 8,nparam);
2204                     TOLONG(d.data.ptr + 10,paramidx);
2205                     break;
2206             }
2207 
2208             typidx = cv_debtyp(d);
2209             break;
2210         }
2211 
2212         case TYstruct:
2213         {
2214             if (config.fulltypes == CV8)
2215             {
2216 version (MARS)
2217 {
2218                 typidx = cv8_fwdref(t.Ttag);
2219 }
2220             }
2221             else
2222             {
2223                 int foo = t.Ttag.Stypidx;
2224                 typidx = cv4_struct(t.Ttag,0);
2225                 //printf("struct '%s' %x %x\n", t.Ttag.Sident.ptr, foo, typidx);
2226             }
2227             break;
2228         }
2229 
2230         case TYenum:
2231             if (CPP)
2232             {
2233 version (SCPP)
2234 {
2235                 typidx = cv4_enum(t.Ttag);
2236 }
2237             }
2238             else
2239                 typidx = cv4_fwdenum(t);
2240             break;
2241 
2242 version (SCPP)
2243 {
2244         case TYvtshape:
2245         {   uint count;
2246             ubyte *p;
2247             ubyte descriptor;
2248 
2249             count = 1 + list_nitems(t.Ttag.Sstruct.Svirtual);
2250             d = debtyp_alloc(4 + ((count + 1) >> 1));
2251             p = d.data.ptr;
2252             TOWORD(p,LF_VTSHAPE);
2253             TOWORD(p + 2,count);
2254             descriptor = I32 ? 0x55 : (LARGECODE ? 0x11 : 0);
2255             memset(p + 4,descriptor,(count + 1) >> 1);
2256 
2257             typidx = cv_debtyp(d);
2258             break;
2259         }
2260 
2261         case TYref:
2262         case TYnref:
2263         case TYfref:
2264             attribute |= 0x20;          // indicate reference pointer
2265             goto case;
2266 
2267         case TYmemptr:
2268             tym = tybasic(tym_conv(t)); // convert to C data type
2269             goto L1;                    // and try again
2270 }
2271 
2272 version (MARS)
2273 {
2274         case TYref:
2275         case TYnref:
2276             attribute |= 0x20;          // indicate reference pointer
2277             tym = TYnptr;               // convert to C data type
2278             goto L1;                    // and try again
2279 }
2280 
2281         case TYnullptr:
2282             tym = TYnptr;
2283             next = cv4_typidx(tstypes[TYvoid]);  // rewrite as void*
2284             t = tspvoid;
2285             goto L1;
2286 
2287         // vector types
2288         case TYfloat4:  size = 16; next = dttab4[TYfloat];  goto Larray;
2289         case TYdouble2: size = 16; next = dttab4[TYdouble]; goto Larray;
2290         case TYschar16: size = 16; next = dttab4[TYschar];  goto Larray;
2291         case TYuchar16: size = 16; next = dttab4[TYuchar];  goto Larray;
2292         case TYshort8:  size = 16; next = dttab4[TYshort];  goto Larray;
2293         case TYushort8: size = 16; next = dttab4[TYushort]; goto Larray;
2294         case TYlong4:   size = 16; next = dttab4[TYlong];   goto Larray;
2295         case TYulong4:  size = 16; next = dttab4[TYulong];  goto Larray;
2296         case TYllong2:  size = 16; next = dttab4[TYllong];  goto Larray;
2297         case TYullong2: size = 16; next = dttab4[TYullong]; goto Larray;
2298 
2299         case TYfloat8:   size = 32; next = dttab4[TYfloat];  goto Larray;
2300         case TYdouble4:  size = 32; next = dttab4[TYdouble]; goto Larray;
2301         case TYschar32:  size = 32; next = dttab4[TYschar];  goto Larray;
2302         case TYuchar32:  size = 32; next = dttab4[TYuchar];  goto Larray;
2303         case TYshort16:  size = 32; next = dttab4[TYshort];  goto Larray;
2304         case TYushort16: size = 32; next = dttab4[TYushort]; goto Larray;
2305         case TYlong8:    size = 32; next = dttab4[TYlong];   goto Larray;
2306         case TYulong8:   size = 32; next = dttab4[TYulong];  goto Larray;
2307         case TYllong4:   size = 32; next = dttab4[TYllong];  goto Larray;
2308         case TYullong4:  size = 32; next = dttab4[TYullong]; goto Larray;
2309 
2310         case TYfloat16:  size = 64; next = dttab4[TYfloat];  goto Larray;
2311         case TYdouble8:  size = 64; next = dttab4[TYdouble]; goto Larray;
2312         case TYschar64:  size = 64; next = dttab4[TYschar];  goto Larray;
2313         case TYuchar64:  size = 64; next = dttab4[TYuchar];  goto Larray;
2314         case TYshort32:  size = 64; next = dttab4[TYshort];  goto Larray;
2315         case TYushort32: size = 64; next = dttab4[TYushort]; goto Larray;
2316         case TYlong16:   size = 64; next = dttab4[TYlong];   goto Larray;
2317         case TYulong16:  size = 64; next = dttab4[TYulong];  goto Larray;
2318         case TYllong8:   size = 64; next = dttab4[TYllong];  goto Larray;
2319         case TYullong8:  size = 64; next = dttab4[TYullong]; goto Larray;
2320 
2321         default:
2322             debug
2323             printf("%s\n", tym_str(tym));
2324 
2325             assert(0);
2326     }
2327 
2328     // Add in const and/or volatile modifiers
2329     if (tycv & (mTYconst | mTYimmutable | mTYvolatile))
2330     {   uint modifier;
2331 
2332         modifier = (tycv & (mTYconst | mTYimmutable)) ? 1 : 0;
2333         modifier |= (tycv & mTYvolatile) ? 2 : 0;
2334         switch (config.fulltypes)
2335         {
2336             case CV8:
2337                 d = debtyp_alloc(8);
2338                 TOWORD(d.data.ptr,0x1001);
2339                 TOLONG(d.data.ptr + 2,typidx);
2340                 TOWORD(d.data.ptr + 6,modifier);
2341                 break;
2342 
2343             case CV4:
2344                 d = debtyp_alloc(6);
2345                 TOWORD(d.data.ptr,LF_MODIFIER);
2346                 TOWORD(d.data.ptr + 2,modifier);
2347                 TOWORD(d.data.ptr + 4,typidx);
2348                 break;
2349 
2350             default:
2351                 d = debtyp_alloc(10);
2352                 TOWORD(d.data.ptr,LF_MODIFIER);
2353                 TOLONG(d.data.ptr + 2,modifier);
2354                 TOLONG(d.data.ptr + 6,typidx);
2355                 break;
2356         }
2357         typidx = cv_debtyp(d);
2358     }
2359 
2360     assert(typidx);
2361     return typidx;
2362 }
2363 
2364 /******************************************
2365  * Write out symbol s.
2366  */
2367 
2368 @trusted
2369 private void cv4_outsym(Symbol *s)
2370 {
2371     uint len;
2372     type *t;
2373     uint length;
2374     uint u;
2375     tym_t tym;
2376     const(char)* id;
2377     ubyte *debsym = null;
2378     ubyte[64] buf = void;
2379 
2380     //printf("cv4_outsym(%s)\n",s.Sident.ptr);
2381     symbol_debug(s);
2382 version (MARS)
2383 {
2384     if (s.Sflags & SFLnodebug)
2385         return;
2386 }
2387     t = s.Stype;
2388     type_debug(t);
2389     tym = tybasic(t.Tty);
2390     if (tyfunc(tym) && s.Sclass != SC.typedef_)
2391     {   int framedatum,targetdatum,fd;
2392         char idfree;
2393         idx_t typidx;
2394 
2395         if (s != funcsym_p)
2396             return;
2397 version (SCPP)
2398 {
2399         if (CPP && isclassmember(s))            // if method
2400         {
2401             OutBuffer buf2;
2402             param_tostring(&buf2,s.Stype);
2403             buf2.prependBytes(cpp_prettyident(s));
2404             char* s2 = buf2.toString();
2405             const len2 = strlen(s2);
2406             id = cast(char*)alloca(len2 + 1);
2407             assert(id);
2408             memcpy(cast(void*)id, s2, len2 + 1);
2409         }
2410         else
2411         {
2412             id = prettyident(s);
2413         }
2414 }
2415 else
2416 {
2417         id = s.prettyIdent ? s.prettyIdent : s.Sident.ptr;
2418 }
2419         len = cv_stringbytes(id);
2420 
2421         // Length of record
2422         length = 2 + 2 + 4 * 3 + _tysize[TYint] * 4 + 2 + cgcv.sz_idx + 1;
2423         debsym = (length + len <= (buf).sizeof) ? buf.ptr : cast(ubyte *) malloc(length + len);
2424         if (!debsym)
2425             err_nomem();
2426         memset(debsym,0,length + len);
2427 
2428         // Symbol type
2429         u = (s.Sclass == SC.static_) ? S_LPROC16 : S_GPROC16;
2430         if (I32)
2431             u += S_GPROC32 - S_GPROC16;
2432         TOWORD(debsym + 2,u);
2433 
2434         if (config.fulltypes == CV4)
2435         {
2436             // Offsets
2437             if (I32)
2438             {   TOLONG(debsym + 16,cast(uint)s.Ssize);           // proc length
2439                 TOLONG(debsym + 20,cast(uint)startoffset);        // debug start
2440                 TOLONG(debsym + 24,cast(uint)retoffset);          // debug end
2441                 u = 28;                                 // offset to fixup
2442             }
2443             else
2444             {   TOWORD(debsym + 16,cast(uint)s.Ssize);           // proc length
2445                 TOWORD(debsym + 18,cast(uint)startoffset);        // debug start
2446                 TOWORD(debsym + 20,cast(uint)retoffset);          // debug end
2447                 u = 22;                                 // offset to fixup
2448             }
2449             length += cv_namestring(debsym + u + _tysize[TYint] + 2 + cgcv.sz_idx + 1,id);
2450             typidx = cv4_symtypidx(s);
2451             TOIDX(debsym + u + _tysize[TYint] + 2,typidx);     // proc type
2452             debsym[u + _tysize[TYint] + 2 + cgcv.sz_idx] = tyfarfunc(tym) ? 4 : 0;
2453             TOWORD(debsym,length - 2);
2454         }
2455         else
2456         {
2457             // Offsets
2458             if (I32)
2459             {   TOLONG(debsym + 16 + cgcv.sz_idx,cast(uint)s.Ssize);             // proc length
2460                 TOLONG(debsym + 20 + cgcv.sz_idx,cast(uint)startoffset);  // debug start
2461                 TOLONG(debsym + 24 + cgcv.sz_idx,cast(uint)retoffset);            // debug end
2462                 u = 28;                                         // offset to fixup
2463             }
2464             else
2465             {   TOWORD(debsym + 16 + cgcv.sz_idx,cast(uint)s.Ssize);             // proc length
2466                 TOWORD(debsym + 18 + cgcv.sz_idx,cast(uint)startoffset);  // debug start
2467                 TOWORD(debsym + 20 + cgcv.sz_idx,cast(uint)retoffset);            // debug end
2468                 u = 22;                                         // offset to fixup
2469             }
2470             u += cgcv.sz_idx;
2471             length += cv_namestring(debsym + u + _tysize[TYint] + 2 + 1,id);
2472             typidx = cv4_symtypidx(s);
2473             TOIDX(debsym + 16,typidx);                  // proc type
2474             debsym[u + _tysize[TYint] + 2] = tyfarfunc(tym) ? 4 : 0;
2475             TOWORD(debsym,length - 2);
2476         }
2477 
2478         uint soffset = cast(uint)Offset(DEBSYM);
2479         objmod.write_bytes(SegData[DEBSYM],length,debsym);
2480 
2481         // Put out fixup for function start offset
2482         objmod.reftoident(DEBSYM,soffset + u,s,0,CFseg | CFoff);
2483     }
2484     else
2485     {   targ_size_t base;
2486         int reg;
2487         uint fd;
2488         uint idx1,idx2;
2489         uint value;
2490         uint fixoff;
2491         idx_t typidx;
2492 
2493         typidx = cv4_typidx(t);
2494 version (MARS)
2495 {
2496         id = s.prettyIdent ? s.prettyIdent : prettyident(s);
2497 }
2498 else
2499 {
2500         id = prettyident(s);
2501 }
2502         len = cast(uint)strlen(id);
2503         debsym = (39 + IDOHD + len <= (buf).sizeof) ? buf.ptr : cast(ubyte *) malloc(39 + IDOHD + len);
2504         if (!debsym)
2505             err_nomem();
2506         switch (s.Sclass)
2507         {
2508             case SC.parameter:
2509             case SC.regpar:
2510                 if (s.Sfl == FLreg)
2511                 {
2512                     s.Sfl = FLpara;
2513                     cv4_outsym(s);
2514                     s.Sfl = FLreg;
2515                     goto case_register;
2516                 }
2517                 base = Para.size - BPoff;    // cancel out add of BPoff
2518                 goto L1;
2519 
2520             case SC.auto_:
2521                 if (s.Sfl == FLreg)
2522                     goto case_register;
2523             case_auto:
2524                 base = Auto.size;
2525             L1:
2526                 if (s.Sscope) // local variables moved into the closure cannot be emitted directly
2527                     goto Lret;
2528                 TOWORD(debsym + 2,I32 ? S_BPREL32 : S_BPREL16);
2529                 if (config.fulltypes == CV4)
2530                 {   TOOFFSET(debsym + 4,s.Soffset + base + BPoff);
2531                     TOIDX(debsym + 4 + _tysize[TYint],typidx);
2532                 }
2533                 else
2534                 {   TOOFFSET(debsym + 4 + cgcv.sz_idx,s.Soffset + base + BPoff);
2535                     TOIDX(debsym + 4,typidx);
2536                 }
2537                 length = 2 + 2 + _tysize[TYint] + cgcv.sz_idx;
2538                 length += cv_namestring(debsym + length,id);
2539                 TOWORD(debsym,length - 2);
2540                 break;
2541 
2542             case SC.bprel:
2543                 base = -BPoff;
2544                 goto L1;
2545 
2546             case SC.fastpar:
2547                 if (s.Sfl != FLreg)
2548                 {   base = Fast.size;
2549                     goto L1;
2550                 }
2551                 goto case_register;
2552 
2553             case SC.register:
2554                 if (s.Sfl != FLreg)
2555                     goto case_auto;
2556                 goto case_register;
2557 
2558             case SC.pseudo:
2559             case_register:
2560                 TOWORD(debsym + 2,S_REGISTER);
2561                 reg = cv_regnum(s);
2562                 TOIDX(debsym + 4,typidx);
2563                 TOWORD(debsym + 4 + cgcv.sz_idx,reg);
2564                 length = 2 * 3 + cgcv.sz_idx;
2565                 length += 1 + cv_namestring(debsym + length,id);
2566                 TOWORD(debsym,length - 2);
2567                 break;
2568 
2569             case SC.extern_:
2570             case SC.comdef:
2571                 // Common blocks have a non-zero Sxtrnnum and an UNKNOWN seg
2572                 if (!(s.Sxtrnnum && s.Sseg == UNKNOWN)) // if it's not really a common block
2573                 {
2574                         goto Lret;
2575                 }
2576                 goto case;
2577             case SC.global:
2578             case SC.comdat:
2579                 u = S_GDATA16;
2580                 goto L2;
2581 
2582             case SC.static_:
2583             case SC.locstat:
2584                 u = S_LDATA16;
2585             L2:
2586                 if (I32)
2587                     u += S_GDATA32 - S_GDATA16;
2588                 TOWORD(debsym + 2,u);
2589                 if (config.fulltypes == CV4)
2590                 {
2591                     fixoff = 4;
2592                     length = 2 + 2 + _tysize[TYint] + 2;
2593                     TOOFFSET(debsym + fixoff,s.Soffset);
2594                     TOWORD(debsym + fixoff + _tysize[TYint],0);
2595                     TOIDX(debsym + length,typidx);
2596                 }
2597                 else
2598                 {
2599                     fixoff = 8;
2600                     length = 2 + 2 + _tysize[TYint] + 2;
2601                     TOOFFSET(debsym + fixoff,s.Soffset);
2602                     TOWORD(debsym + fixoff + _tysize[TYint],0);        // segment
2603                     TOIDX(debsym + 4,typidx);
2604                 }
2605                 length += cgcv.sz_idx;
2606                 length += cv_namestring(debsym + length,id);
2607                 TOWORD(debsym,length - 2);
2608                 assert(length <= 40 + len);
2609 
2610                 if (s.Sseg == UNKNOWN || s.Sclass == SC.comdat) // if common block
2611                 {
2612                     if (config.exe & EX_flat)
2613                     {
2614                         fd = 0x16;
2615                         idx1 = DGROUPIDX;
2616                         idx2 = s.Sxtrnnum;
2617                     }
2618                     else
2619                     {
2620                         fd = 0x26;
2621                         idx1 = idx2 = s.Sxtrnnum;
2622                     }
2623                 }
2624                 else if (s.ty() & (mTYfar | mTYcs))
2625                 {
2626                     fd = 0x04;
2627                     idx1 = idx2 = SegData[s.Sseg].segidx;
2628                 }
2629                 else
2630                 {   fd = 0x14;
2631                     idx1 = DGROUPIDX;
2632                     idx2 = SegData[s.Sseg].segidx;
2633                 }
2634                 /* Because of the linker limitations, the length cannot
2635                  * exceed 0x1000.
2636                  * See optlink\cv\cvhashes.asm
2637                  */
2638                 assert(length <= 0x1000);
2639                 if (idx2 != 0)
2640                 {   uint offset = cast(uint)Offset(DEBSYM);
2641                     objmod.write_bytes(SegData[DEBSYM],length,debsym);
2642                     objmod.write_long(DEBSYM,offset + fixoff,cast(uint)s.Soffset,
2643                         cgcv.LCFDpointer + fd,idx1,idx2);
2644                 }
2645                 goto Lret;
2646 
2647 static if (1)
2648 {
2649             case SC.typedef_:
2650                 s.Stypidx = typidx;
2651                 reset_symbuf.write((&s)[0 .. 1]);
2652                 goto L4;
2653 
2654             case SC.struct_:
2655                 if (s.Sstruct.Sflags & STRnotagname)
2656                     goto Lret;
2657                 goto L4;
2658 
2659             case SC.enum_:
2660 version (SCPP)
2661 {
2662                 if (CPP && s.Senum.SEflags & SENnotagname)
2663                     goto Lret;
2664 }
2665             L4:
2666                 // Output a 'user-defined type' for the tag name
2667                 TOWORD(debsym + 2,S_UDT);
2668                 TOIDX(debsym + 4,typidx);
2669                 length = 2 + 2 + cgcv.sz_idx;
2670                 length += cv_namestring(debsym + length,id);
2671                 TOWORD(debsym,length - 2);
2672                 list_subtract(&cgcv.list,s);
2673                 break;
2674 
2675             case SC.const_:
2676                 // The only constants are enum members
2677                 value = cast(uint)el_tolongt(s.Svalue);
2678                 TOWORD(debsym + 2,S_CONST);
2679                 TOIDX(debsym + 4,typidx);
2680                 length = 4 + cgcv.sz_idx;
2681                 cv4_storenumeric(debsym + length,value);
2682                 length += cv4_numericbytes(value);
2683                 length += cv_namestring(debsym + length,id);
2684                 TOWORD(debsym,length - 2);
2685                 break;
2686 }
2687             default:
2688                 goto Lret;
2689         }
2690         assert(length <= 40 + len);
2691         objmod.write_bytes(SegData[DEBSYM],length,debsym);
2692     }
2693 Lret:
2694     if (debsym != buf.ptr)
2695         free(debsym);
2696 }
2697 
2698 /******************************************
2699  * Write out any deferred symbols.
2700  */
2701 
2702 @trusted
2703 private void cv_outlist()
2704 {
2705     while (cgcv.list)
2706         cv_outsym(cast(Symbol *) list_pop(&cgcv.list));
2707 }
2708 
2709 /******************************************
2710  * Write out symbol table for current function.
2711  */
2712 
2713 @trusted
2714 private void cv4_func(Funcsym *s, ref symtab_t symtab)
2715 {
2716     int endarg;
2717 
2718     cv4_outsym(s);              // put out function symbol
2719 version (MARS)
2720 {
2721     __gshared Funcsym* sfunc;
2722     __gshared int cntOpenBlocks;
2723     sfunc = s;
2724     cntOpenBlocks = 0;
2725 
2726     struct cv4
2727     {
2728     nothrow:
2729         // record for CV record S_BLOCK32
2730         struct block32_data
2731         {
2732             ushort len;
2733             ushort id;
2734             uint pParent;
2735             uint pEnd;
2736             uint length;
2737             uint offset;
2738             ushort seg;
2739             ubyte[2] name;
2740         }
2741 
2742       extern (C++):
2743 
2744         static void endArgs()
2745         {
2746             __gshared ushort[2] endargs = [ 2, S_ENDARG ];
2747             objmod.write_bytes(SegData[DEBSYM],(endargs).sizeof,endargs.ptr);
2748         }
2749         static void beginBlock(int offset, int length)
2750         {
2751             if (++cntOpenBlocks >= 255)
2752                 return; // optlink does not like more than 255 scope blocks
2753 
2754             uint soffset = cast(uint)Offset(DEBSYM);
2755             // parent and end to be filled by linker
2756             block32_data block32 = { (block32_data).sizeof - 2, S_BLOCK32, 0, 0, length, 0, 0, [ 0, '\0' ] };
2757             objmod.write_bytes(SegData[DEBSYM], (block32).sizeof, &block32);
2758             size_t offOffset = cast(char*)&block32.offset - cast(char*)&block32;
2759             objmod.reftoident(DEBSYM, soffset + offOffset, sfunc, offset + sfunc.Soffset, CFseg | CFoff);
2760         }
2761         static void endBlock()
2762         {
2763             if (cntOpenBlocks-- >= 255)
2764                 return; // optlink does not like more than 255 scope blocks
2765 
2766             __gshared ushort[2] endargs = [ 2, S_END ];
2767             objmod.write_bytes(SegData[DEBSYM],(endargs).sizeof,endargs.ptr);
2768         }
2769     }
2770 
2771     varStats_writeSymbolTable(symtab, &cv4_outsym, &cv4.endArgs, &cv4.beginBlock, &cv4.endBlock);
2772 }
2773 else
2774 {
2775     // Put out local symbols
2776     endarg = 0;
2777     foreach (sa; symtab[])
2778     {   //printf("symtab[%d] = %p\n",si,symtab[si]);
2779         cv4_outsym(sa);
2780     }
2781 }
2782 
2783     // Put out function return record
2784     if (1)
2785     {   ubyte[2+2+2+1+1+4] sreturn = void;
2786         ushort flags;
2787         ubyte style;
2788         tym_t ty;
2789         tym_t tyret;
2790         uint u;
2791 
2792         u = 2+2+1;
2793         ty = tybasic(s.ty());
2794 
2795         flags = tyrevfunc(ty) ? 0 : 1;
2796         flags |= typfunc(ty) ? 0 : 2;
2797         TOWORD(sreturn.ptr + 4,flags);
2798 
2799         tyret = tybasic(s.Stype.Tnext.Tty);
2800         switch (tyret)
2801         {
2802             case TYvoid:
2803             default:
2804                 style = 0;
2805                 break;
2806 
2807             case TYbool:
2808             case TYchar:
2809             case TYschar:
2810             case TYuchar:
2811                 sreturn[7] = 1;
2812                 sreturn[8] = 1;         // AL
2813                 goto L1;
2814 
2815             case TYwchar_t:
2816             case TYchar16:
2817             case TYshort:
2818             case TYushort:
2819                 goto case_ax;
2820 
2821             case TYint:
2822             case TYuint:
2823             case TYsptr:
2824             case TYcptr:
2825             case TYnullptr:
2826             case TYnptr:
2827             case TYnref:
2828                 if (I32)
2829                     goto case_eax;
2830                 else
2831                     goto case_ax;
2832 
2833             case TYfloat:
2834             case TYifloat:
2835                 if (config.exe & EX_flat)
2836                     goto case_st0;
2837                 goto case;
2838 
2839             case TYlong:
2840             case TYulong:
2841             case TYdchar:
2842                 if (I32)
2843                     goto case_eax;
2844                 else
2845                     goto case_dxax;
2846 
2847             case TYfptr:
2848             case TYhptr:
2849                 if (I32)
2850                     goto case_edxeax;
2851                 else
2852                     goto case_dxax;
2853 
2854             case TYvptr:
2855                 if (I32)
2856                     goto case_edxebx;
2857                 else
2858                     goto case_dxbx;
2859 
2860             case TYdouble:
2861             case TYidouble:
2862             case TYdouble_alias:
2863                 if (config.exe & EX_flat)
2864                     goto case_st0;
2865                 if (I32)
2866                     goto case_edxeax;
2867                 else
2868                     goto case_axbxcxdx;
2869 
2870             case TYllong:
2871             case TYullong:
2872                 assert(I32);
2873                 goto case_edxeax;
2874 
2875             case TYldouble:
2876             case TYildouble:
2877                 goto case_st0;
2878 
2879             case TYcfloat:
2880             case TYcdouble:
2881             case TYcldouble:
2882                 goto case_st01;
2883 
2884             case_ax:
2885                 sreturn[7] = 1;
2886                 sreturn[8] = 9;         // AX
2887                 goto L1;
2888 
2889             case_eax:
2890                 sreturn[7] = 1;
2891                 sreturn[8] = 17;        // EAX
2892                 goto L1;
2893 
2894 
2895             case_dxax:
2896                 sreturn[7] = 2;
2897                 sreturn[8] = 11;        // DX
2898                 sreturn[9] = 9;         // AX
2899                 goto L1;
2900 
2901             case_dxbx:
2902                 sreturn[7] = 2;
2903                 sreturn[8] = 11;        // DX
2904                 sreturn[9] = 12;        // BX
2905                 goto L1;
2906 
2907             case_axbxcxdx:
2908                 sreturn[7] = 4;
2909                 sreturn[8] = 9;         // AX
2910                 sreturn[9] = 12;        // BX
2911                 sreturn[10] = 10;       // CX
2912                 sreturn[11] = 11;       // DX
2913                 goto L1;
2914 
2915             case_edxeax:
2916                 sreturn[7] = 2;
2917                 sreturn[8] = 19;        // EDX
2918                 sreturn[9] = 17;        // EAX
2919                 goto L1;
2920 
2921             case_edxebx:
2922                 sreturn[7] = 2;
2923                 sreturn[8] = 19;        // EDX
2924                 sreturn[9] = 20;        // EBX
2925                 goto L1;
2926 
2927             case_st0:
2928                 sreturn[7] = 1;
2929                 sreturn[8] = 128;       // ST0
2930                 goto L1;
2931 
2932             case_st01:
2933                 sreturn[7] = 2;
2934                 sreturn[8] = 128;       // ST0 (imaginary)
2935                 sreturn[9] = 129;       // ST1 (real)
2936                 goto L1;
2937 
2938             L1:
2939                 style = 1;
2940                 u += sreturn[7] + 1;
2941                 break;
2942         }
2943         sreturn[6] = style;
2944 
2945         TOWORD(sreturn.ptr,u);
2946         TOWORD(sreturn.ptr + 2,S_RETURN);
2947         objmod.write_bytes(SegData[DEBSYM],u + 2,sreturn.ptr);
2948     }
2949 
2950     // Put out end scope
2951     {   __gshared ushort[2] endproc = [ 2,S_END ];
2952 
2953         objmod.write_bytes(SegData[DEBSYM],(endproc).sizeof,endproc.ptr);
2954     }
2955 
2956     cv_outlist();
2957 }
2958 
2959 //////////////////////////////////////////////////////////
2960 
2961 /******************************************
2962  * Write out data to .OBJ file.
2963  */
2964 
2965 @trusted
2966 void cv_term()
2967 {
2968     //printf("cv_term(): debtyp.length = %d\n",debtyp.length);
2969 
2970     segidx_t typeseg = objmod.seg_debugT();
2971 
2972     switch (config.fulltypes)
2973     {
2974         case CV4:
2975         case CVSYM:
2976             cv_outlist();
2977             goto case;
2978         case CV8:
2979             objmod.write_bytes(SegData[typeseg],4,&cgcv.signature);
2980             if (debtyp.length != 1 || config.fulltypes == CV8)
2981             {
2982                 for (uint u = 0; u < debtyp.length; u++)
2983                 {   debtyp_t *d = debtyp[u];
2984 
2985                     objmod.write_bytes(SegData[typeseg],2 + d.length,cast(char *)d + uint.sizeof);
2986                     debtyp_free(d);
2987                 }
2988             }
2989             else if (debtyp.length)
2990             {
2991                 debtyp_free(debtyp[0]);
2992             }
2993             break;
2994 
2995 
2996         default:
2997             assert(0);
2998     }
2999 
3000     // debtyp.dtor();  // save for later
3001     vec_free(debtypvec);
3002     debtypvec = null;
3003 }
3004 
3005 /******************************************
3006  * Write out symbol table for current function.
3007  */
3008 
3009 @trusted
3010 void cv_func(Funcsym *s)
3011 {
3012 version (SCPP)
3013 {
3014     if (errcnt)                 // if we had any errors
3015         return;                 // don't bother putting stuff in .OBJ file
3016 }
3017 
3018     //printf("cv_func('%s')\n",s.Sident.ptr);
3019 version (MARS)
3020 {
3021     if (s.Sflags & SFLnodebug)
3022         return;
3023 }
3024 else
3025 {
3026     if (CPP && s.Sfunc.Fflags & Fnodebug)     // if don't generate debug info
3027         return;
3028 }
3029     switch (config.fulltypes)
3030     {
3031         case CV4:
3032         case CVSYM:
3033         case CVTDB:
3034             cv4_func(s, globsym);
3035             break;
3036 
3037         default:
3038             assert(0);
3039     }
3040 }
3041 
3042 /******************************************
3043  * Write out symbol table for current function.
3044  */
3045 
3046 @trusted
3047 void cv_outsym(Symbol *s)
3048 {
3049     //printf("cv_outsym('%s')\n",s.Sident.ptr);
3050     symbol_debug(s);
3051 version (MARS)
3052 {
3053     if (s.Sflags & SFLnodebug)
3054         return;
3055 }
3056     switch (config.fulltypes)
3057     {
3058         case CV4:
3059         case CVSYM:
3060         case CVTDB:
3061             cv4_outsym(s);
3062             break;
3063 
3064 version (MARS)
3065 {
3066         case CV8:
3067             cv8_outsym(s);
3068             break;
3069 }
3070 
3071         default:
3072             assert(0);
3073     }
3074 }
3075 
3076 /******************************************
3077  * Return cv type index for a type.
3078  */
3079 
3080 @trusted
3081 uint cv_typidx(type *t)
3082 {   uint ti;
3083 
3084     //printf("cv_typidx(%p)\n",t);
3085     switch (config.fulltypes)
3086     {
3087         case CV4:
3088         case CVTDB:
3089         case CVSYM:
3090         case CV8:
3091             ti = cv4_typidx(t);
3092             break;
3093 
3094         default:
3095             debug
3096             printf("fulltypes = %d\n",config.fulltypes);
3097 
3098             assert(0);
3099     }
3100     return ti;
3101 }
3102 
3103 }