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