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