1 /**
2  * CodeView 4 symbolic debug info generation
3  *
4  * Compiler implementation of the
5  * $(LINK2 https://www.dlang.org, D programming language).
6  *
7  * Copyright:   Copyright (C) 1984-1995 by Symantec
8  *              Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved
9  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
10  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/dcgcv.d, backend/dcgcv.d)
12  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/dcgcv.d
13  */
14 
15 module dmd.backend.dcgcv;
16 
17 import core.stdc.stdio;
18 import core.stdc.stdlib;
19 import core.stdc.string;
20 
21 import dmd.backend.cc;
22 import dmd.backend.cdef;
23 import dmd.backend.cgcv;
24 import dmd.backend.code;
25 import dmd.backend.code_x86;
26 import dmd.backend.cv4;
27 import dmd.backend.dlist;
28 import dmd.backend.dvec;
29 import dmd.backend.el;
30 import dmd.backend.global;
31 import dmd.backend.mem;
32 import dmd.backend.obj;
33 import dmd.backend.symtab;
34 import dmd.backend.ty;
35 import dmd.backend.type;
36 
37 import dmd.backend.barray;
38 
39 import dmd.common.outbuffer;
40 
41 import dmd.backend.dvarstats;
42 
43 
44 nothrow:
45 @safe:
46 
47 @trusted
48 extern (C) void TOOFFSET(void* p, targ_size_t value)
49 {
50     switch (_tysize[TYnptr])
51     {
52         case 2: *cast(ushort*)p = cast(ushort)value; break;
53         case 4: *cast(uint*)  p = cast(uint)  value; break;
54         case 8: *cast(ulong*) p = cast(ulong) value; break;
55         default:
56             assert(0);
57     }
58 }
59 
60 import dmd.backend.var : ftdbname;
61 
62 // Convert from SFL visibilities to CV4 protections
63 uint SFLtoATTR(uint sfl) { return 4 - ((sfl & SFLpmask) >> 5); }
64 
65 __gshared
66 {
67 
68 /* Dynamic array of debtyp_t's  */
69 private Barray!(debtyp_t*) debtyp;
70 
71 private vec_t debtypvec;     // vector of used entries
72 enum DEBTYPVECDIM = 16_001;   //8009 //3001     // dimension of debtypvec (should be prime)
73 
74 enum DEBTYPHASHDIM = 1009;
75 private uint[DEBTYPHASHDIM] debtyphash;
76 
77 private OutBuffer *reset_symbuf; // Keep pointers to reset symbols
78 
79 @trusted
80 idx_t DEB_NULL() { return cgcv.deb_offset; }        // index of null debug type record
81 
82 /* This limitation is because of 4K page sizes
83  * in optlink/cv/cvhashes.asm
84  */
85 enum CVIDMAX = (0xFF0-20);   // the -20 is picked by trial and error
86 
87 enum LOCATsegrel = 0xC000;
88 
89 /* Unfortunately, the fixup stuff is different for EASY OMF and Microsoft */
90 enum EASY_LCFDoffset  =      (LOCATsegrel | 0x1404);
91 enum EASY_LCFDpointer =      (LOCATsegrel | 0x1800);
92 
93 enum LCFD32offset     =      (LOCATsegrel | 0x2404);
94 enum LCFD32pointer    =      (LOCATsegrel | 0x2C00);
95 enum LCFD16pointer    =      (LOCATsegrel | 0x0C00);
96 }
97 
98 enum MARS = true;
99 
100 /******************************************
101  * Return number of bytes consumed in OBJ file by a name.
102  */
103 
104 @trusted
105 int cv_stringbytes(const(char)* name)
106 {
107     int len = cast(int)strlen(name);
108     if (config.fulltypes == CV8)
109         return len + 1;
110     if (len > CVIDMAX)
111         len = CVIDMAX;
112     return len + ((len > 255) ? 4 : 1);
113 }
114 
115 /******************************************
116  * Stuff a namestring into p.
117  * Returns:
118  *      number of bytes consumed
119  */
120 
121 @trusted
122 int cv_namestring(ubyte *p, const(char)* name, int length = -1)
123 {
124     size_t len = (length >= 0) ? length : strlen(name);
125     if (config.fulltypes == CV8)
126     {
127         size_t numBytesWritten = len + ((length < 0) ? 1 : 0);
128         memcpy(p, name, numBytesWritten);
129         if(config.flags2 & CFG2gms)
130         {
131             for(int i = 0; i < len; i++)
132             {
133                 if(p[i] == '.')
134                     p[i] = '@';
135             }
136         }
137         return cast(int)numBytesWritten;
138     }
139     if (len > 255)
140     {   p[0] = 0xFF;
141         p[1] = 0;
142         if (len > CVIDMAX)
143             len = CVIDMAX;
144         TOWORD(p + 2,cast(uint)len);
145         memcpy(p + 4,name,len);
146         len += 4;
147     }
148     else
149     {   p[0] = cast(ubyte)len;
150         memcpy(p + 1,name,len);
151         len++;
152     }
153     return cast(int)len;
154 }
155 
156 /***********************************
157  * Compute debug register number for symbol s.
158  * Returns:
159  *      0..7    byte registers
160  *      8..15   word registers
161  *      16..23  dword registers
162  */
163 
164 @trusted
165 private int cv_regnum(Symbol *s)
166 {
167     uint reg = s.Sreglsw;
168     if (s.Sclass == SC.pseudo)
169     {
170     }
171     else
172     {
173         assert(reg < 8);
174         assert(s.Sfl == FLreg);
175         switch (type_size(s.Stype))
176         {
177             case LONGSIZE:
178             case 3:             reg += 8;
179                                 goto case;
180 
181             case SHORTSIZE:     reg += 8;
182                                 goto case;
183 
184             case CHARSIZE:      break;
185 
186             case LLONGSIZE:
187                 reg += (s.Sregmsw << 8) + (16 << 8) + 16;
188                 if (config.fulltypes == CV4)
189                     reg += (1 << 8);
190                 break;
191 
192             default:
193 static if (0)
194 {
195                 symbol_print(s);
196                 type_print(s.Stype);
197                 printf("size = %d\n",type_size(s.Stype));
198 }
199                 assert(0);
200         }
201     }
202     if (config.fulltypes == CV4)
203         reg++;
204     return reg;
205 }
206 
207 /***********************************
208  * Allocate a debtyp_t.
209  */
210 @trusted
211 debtyp_t * debtyp_alloc(uint length)
212 {
213     debtyp_t *d;
214     uint pad = 0;
215 
216     //printf("len = %u, x%x\n", length, length);
217     if (config.fulltypes == CV8)
218     {   // length+2 must lie on 4 byte boundary
219         pad = ((length + 2 + 3) & ~3) - (length + 2);
220         length += pad;
221     }
222 
223     if (length > ushort.max)
224         err_nomem();
225 
226     const len = debtyp_t.sizeof - (d.data).sizeof + length;
227 debug
228 {
229     d = cast(debtyp_t *) mem_malloc(len /*+ 1*/);
230     memset(d, 0xAA, len);
231 //    (cast(char*)d)[len] = 0x2E;
232 }
233 else
234 {
235     d = cast(debtyp_t *) malloc(debtyp_t.sizeof - (d.data).sizeof + length);
236     if (!d)
237         err_nomem();
238 }
239     d.length = cast(ushort)length;
240     if (pad)
241     {
242         __gshared const ubyte[3] padx = [0xF3, 0xF2, 0xF1];
243         memcpy(d.data.ptr + length - pad, padx.ptr + 3 - pad, pad);
244     }
245     //printf("debtyp_alloc(%d) = %p\n", length, d);
246     return d;
247 }
248 
249 /***********************************
250  * Free a debtyp_t.
251  */
252 
253 @trusted
254 private void debtyp_free(debtyp_t *d)
255 {
256     //printf("debtyp_free(length = %d, %p)\n", d.length, d);
257     //fflush(stdout);
258 debug
259 {
260     assert(d.length <= ushort.max);
261     uint len = debtyp_t.sizeof - (d.data).sizeof + d.length;
262 //    assert((cast(char*)d)[len] == 0x2E);
263     memset(d, 0x55, len);
264     mem_free(d);
265 }
266 else
267 {
268     free(d);
269 }
270 }
271 
272 static if (0)
273 {
274 void debtyp_check(debtyp_t *d,int linnum)
275 {   int i;
276     __gshared char c;
277 
278     //printf("linnum = %d\n",linnum);
279     //printf(" length = %d\n",d.length);
280     for (i = 0; i < d.length; i++)
281         c = d.data.ptr[i];
282 }
283 
284 void debtyp_check(debtyp_t* d) { debtyp_check(d,__LINE__); }
285 }
286 else
287 {
288 void debtyp_check(debtyp_t* d) { }
289 }
290 
291 /***********************************
292  * Search for debtyp_t in debtyp[]. If it is there, return the index
293  * of it, and free d. Otherwise, add it.
294  * Returns:
295  *      index in debtyp[]
296  */
297 
298 @trusted
299 idx_t cv_debtyp(debtyp_t *d)
300 {
301     uint hashi;
302 
303     assert(d);
304     const length = d.length;
305     //printf("length = %3d\n",length);
306     if (length)
307     {
308         uint hash = length;
309         if (length >= uint.sizeof)
310         {
311             // Hash consists of the sum of the first 4 bytes with the last 4 bytes
312             union U { ubyte* cp; uint* up; }
313             U un = void;
314             un.cp = d.data.ptr;
315             hash += *un.up;
316             un.cp += length - uint.sizeof;
317             hash += *un.up;
318         }
319         hashi = hash % DEBTYPHASHDIM;
320         hash %= DEBTYPVECDIM;
321 //printf(" hashi = %d", hashi);
322 
323         if (vec_testbit(hash,debtypvec))
324         {
325 //printf(" test");
326             // Threaded list is much faster
327             for (uint u = debtyphash[hashi]; u; u = debtyp[u].prev)
328             //for (uint u = debtyp.length; u--; )
329             {
330                 if (length == debtyp[u].length &&
331                     memcmp(d.data.ptr,debtyp[u].data.ptr,length) == 0)
332                 {   debtyp_free(d);
333 //printf(" match %d\n",u);
334                     return u + cgcv.deb_offset;
335                 }
336             }
337         }
338         else
339             vec_setbit(hash,debtypvec);
340     }
341     else
342         hashi = 1;
343 //printf(" add   %d\n",debtyp.length);
344     d.prev = debtyphash[hashi];
345     debtyphash[hashi] = cast(uint)debtyp.length;
346 
347     /* It's not already in the array, so add it */
348     debtyp.push(d);
349 
350     return cast(uint)debtyp.length - 1 + cgcv.deb_offset;
351 }
352 
353 @trusted
354 idx_t cv_numdebtypes()
355 {
356     return cast(idx_t)debtyp.length;
357 }
358 
359 /****************************
360  * Store a null record at DEB_NULL.
361  */
362 
363 @trusted
364 void cv_init()
365 {   debtyp_t *d;
366 
367     //printf("cv_init()\n");
368 
369     // Initialize statics
370     debtyp.setLength(0);
371     if (!ftdbname)
372         ftdbname = cast(char *)"symc.tdb".ptr;
373 
374     memset(&cgcv,0,cgcv.sizeof);
375     cgcv.sz_idx = 2;
376     cgcv.LCFDoffset = LCFD32offset;
377     cgcv.LCFDpointer = LCFD16pointer;
378 
379     debtypvec = vec_calloc(DEBTYPVECDIM);
380     memset(debtyphash.ptr,0,debtyphash.sizeof);
381 
382     if (reset_symbuf)
383     {
384         Symbol **p = cast(Symbol **)reset_symbuf.buf;
385         const size_t n = reset_symbuf.length() / (Symbol *).sizeof;
386         for (size_t i = 0; i < n; ++i)
387             symbol_reset(p[i]);
388         reset_symbuf.reset();
389     }
390     else
391     {
392         reset_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
393         if (!reset_symbuf)
394             err_nomem();
395         reset_symbuf.reserve(10 * (Symbol*).sizeof);
396     }
397 
398     /* Reset for different OBJ file formats     */
399     if (I32 || I64)
400     {
401         // Adjust values in old CV tables for 32 bit ints
402         dttab[TYenum] = dttab[TYlong];
403         dttab[TYint]  = dttab[TYlong];
404         dttab[TYuint] = dttab[TYulong];
405 
406         // Adjust Codeview 4 values for 32 bit ints and 32 bit pointer offsets
407         dttab4[TYenum] = 0x74;
408         dttab4[TYint]  = 0x74;
409         dttab4[TYuint] = 0x75;
410         if (I64)
411         {
412             dttab4[TYptr]  = 0x600;
413             dttab4[TYnptr] = 0x600;
414             dttab4[TYsptr] = 0x600;
415             dttab4[TYimmutPtr] = 0x600;
416             dttab4[TYsharePtr] = 0x600;
417             dttab4[TYrestrictPtr] = 0x600;
418             dttab4[TYfgPtr] = 0x600;
419         }
420         else
421         {
422             dttab4[TYptr]  = 0x400;
423             dttab4[TYsptr] = 0x400;
424             dttab4[TYnptr] = 0x400;
425             dttab4[TYimmutPtr] = 0x400;
426             dttab4[TYsharePtr] = 0x400;
427             dttab4[TYrestrictPtr] = 0x400;
428             dttab4[TYfgPtr] = 0x400;
429         }
430         dttab4[TYcptr] = 0x400;
431         dttab4[TYfptr] = 0x500;
432 
433         if (config.flags & CFGeasyomf)
434         {   cgcv.LCFDoffset  = EASY_LCFDoffset;
435             cgcv.LCFDpointer = EASY_LCFDpointer;
436             assert(config.fulltypes == CVOLD);
437         }
438         else
439             cgcv.LCFDpointer = LCFD32pointer;
440 
441         if (config.exe & EX_flat)
442             cgcv.FD_code = 0x10;
443     }
444 
445     if (config.fulltypes >= CV4)
446     {   int flags;
447         __gshared ushort[5] memmodel = [0,0x100,0x20,0x120,0x120];
448         char[1 + (VERSION).sizeof] version_;
449         ubyte[8 + (version_).sizeof] debsym;
450 
451         // Put out signature indicating CV4 format
452         switch (config.fulltypes)
453         {
454             case CV4:
455                 cgcv.signature = 1;
456                 break;
457 
458             case CV8:
459                 cgcv.signature = 4;
460                 break;
461 
462             default:
463             {   const(char)* x = "1MYS";
464                 cgcv.signature = *cast(int *) x;
465                 break;
466             }
467         }
468 
469         cgcv.deb_offset = 0x1000;
470 
471         if (config.fulltypes == CV8)
472         {   cgcv.sz_idx = 4;
473             return;     // figure out rest later
474         }
475 
476         if (config.fulltypes >= CVSYM)
477         {   cgcv.sz_idx = 4;
478             if (!(config.flags2 & CFG2phgen))
479                 cgcv.deb_offset = 0x80000000;
480         }
481 
482         objmod.write_bytes(SegData[DEBSYM],(&cgcv.signature)[0 .. 1]);
483 
484         // Allocate an LF_ARGLIST with no arguments
485         if (config.fulltypes == CV4)
486         {   d = debtyp_alloc(4);
487             TOWORD(d.data.ptr,LF_ARGLIST);
488             TOWORD(d.data.ptr + 2,0);
489         }
490         else
491         {   d = debtyp_alloc(6);
492             TOWORD(d.data.ptr,LF_ARGLIST);
493             TOLONG(d.data.ptr + 2,0);
494         }
495 
496         // Put out S_COMPILE record
497         TOWORD(debsym.ptr + 2,S_COMPILE);
498         switch (config.target_cpu)
499         {
500             case TARGET_8086:   debsym[4] = 0;  break;
501             case TARGET_80286:  debsym[4] = 2;  break;
502             case TARGET_80386:  debsym[4] = 3;  break;
503             case TARGET_80486:  debsym[4] = 4;  break;
504 
505             case TARGET_Pentium:
506             case TARGET_PentiumMMX:
507                                 debsym[4] = 5;  break;
508 
509             case TARGET_PentiumPro:
510             case TARGET_PentiumII:
511                                 debsym[4] = 6;  break;
512             default:    assert(0);
513         }
514         debsym[5] = (CPP != 0);         // 0==C, 1==C++
515         flags = (config.inline8087) ? (0<<3) : (1<<3);
516         if (I32)
517             flags |= 0x80;              // 32 bit addresses
518         flags |= memmodel[config.memmodel];
519         TOWORD(debsym.ptr + 6,flags);
520         version_[0] = 'Z';
521         strcpy(version_.ptr + 1,VERSION);
522         cv_namestring(debsym.ptr + 8,version_.ptr);
523         TOWORD(debsym.ptr,6 + (version_).sizeof);
524         objmod.write_bytes(SegData[DEBSYM], debsym[0 .. 8 + (version_).sizeof]);
525 
526     }
527     else
528     {
529         assert(0);
530     }
531     if (config.fulltypes == CVTDB)
532         cgcv.deb_offset = cv_debtyp(d);
533     else
534         cv_debtyp(d);
535 }
536 
537 /////////////////////////// CodeView 4 ///////////////////////////////
538 
539 /***********************************
540  * Return number of bytes required to store a numeric leaf.
541  */
542 
543 uint cv4_numericbytes(uint value)
544 {   uint u;
545 
546     if (value < 0x8000)
547         u = 2;
548     else if (value < 0x10000)
549         u = 4;
550     else
551         u = 6;
552     return u;
553 }
554 
555 /********************************
556  * Store numeric leaf.
557  * Must use exact same number of bytes as cv4_numericbytes().
558  */
559 
560 @trusted
561 void cv4_storenumeric(ubyte *p, uint value)
562 {
563     if (value < 0x8000)
564         TOWORD(p,value);
565     else if (value < 0x10000)
566     {   TOWORD(p,LF_USHORT);
567         p += 2;
568         TOWORD(p,value);
569     }
570     else
571     {   TOWORD(p,LF_ULONG);
572         *cast(targ_ulong *)(p + 2) = cast(uint) value;
573     }
574 }
575 
576 /***********************************
577  * Return number of bytes required to store a signed numeric leaf.
578  * Params:
579  *   value = value to store
580  * Returns:
581  *   number of bytes required for storing value
582  */
583 uint cv4_signednumericbytes(int value)
584 {
585     uint u;
586     if (value >= 0 && value < 0x8000)
587         u = 2;
588     else if (value == cast(short)value)
589         u = 4;
590     else
591         u = 6;
592     return u;
593 }
594 
595 /********************************
596  * Store signed numeric leaf.
597  * Must use exact same number of bytes as cv4_signednumericbytes().
598  * Params:
599  *   p = address where to store value
600  *   value = value to store
601  */
602 @trusted
603 void cv4_storesignednumeric(ubyte *p, int value)
604 {
605     if (value >= 0 && value < 0x8000)
606         TOWORD(p, value);
607     else if (value == cast(short)value)
608     {
609         TOWORD(p, LF_SHORT);
610         TOWORD(p + 2, value);
611     }
612     else
613     {
614         TOWORD(p,LF_LONG);
615         TOLONG(p + 2, value);
616     }
617 }
618 
619 /*********************************
620  * Generate a type index for a parameter list.
621  */
622 
623 @trusted
624 idx_t cv4_arglist(type *t,uint *pnparam)
625 {   uint u;
626     uint nparam;
627     idx_t paramidx;
628     debtyp_t *d;
629     param_t *p;
630 
631     // Compute nparam, number of parameters
632     nparam = 0;
633     for (p = t.Tparamtypes; p; p = p.Pnext)
634         nparam++;
635     *pnparam = nparam;
636 
637     // Construct an LF_ARGLIST of those parameters
638     if (nparam == 0)
639     {
640         if (config.fulltypes == CV8)
641         {
642             d = debtyp_alloc(2 + 4 + 4);
643             TOWORD(d.data.ptr,LF_ARGLIST_V2);
644             TOLONG(d.data.ptr + 2,1);
645             TOLONG(d.data.ptr + 6,0);
646             paramidx = cv_debtyp(d);
647         }
648         else
649             paramidx = DEB_NULL;
650     }
651     else
652     {
653         switch (config.fulltypes)
654         {
655             case CV8:
656                 d = debtyp_alloc(2 + 4 + nparam * 4);
657                 TOWORD(d.data.ptr,LF_ARGLIST_V2);
658                 TOLONG(d.data.ptr + 2,nparam);
659 
660                 p = t.Tparamtypes;
661                 for (u = 0; u < nparam; u++)
662                 {   TOLONG(d.data.ptr + 6 + u * 4,cv4_typidx(p.Ptype));
663                     p = p.Pnext;
664                 }
665                 break;
666 
667             case CV4:
668                 d = debtyp_alloc(2 + 2 + nparam * 2);
669                 TOWORD(d.data.ptr,LF_ARGLIST);
670                 TOWORD(d.data.ptr + 2,nparam);
671 
672                 p = t.Tparamtypes;
673                 for (u = 0; u < nparam; u++)
674                 {   TOWORD(d.data.ptr + 4 + u * 2,cv4_typidx(p.Ptype));
675                     p = p.Pnext;
676                 }
677                 break;
678 
679             default:
680                 d = debtyp_alloc(2 + 4 + nparam * 4);
681                 TOWORD(d.data.ptr,LF_ARGLIST);
682                 TOLONG(d.data.ptr + 2,nparam);
683 
684                 p = t.Tparamtypes;
685                 for (u = 0; u < nparam; u++)
686                 {   TOLONG(d.data.ptr + 6 + u * 4,cv4_typidx(p.Ptype));
687                     p = p.Pnext;
688                 }
689                 break;
690         }
691         paramidx = cv_debtyp(d);
692     }
693     return paramidx;
694 }
695 
696 /****************************
697  * Return type index of struct.
698  * Input:
699  *      s       struct tag symbol
700  *      flags
701  *          0   generate a reference to s
702  *          1   just saw the definition of s
703  *          2   saw key function for class s
704  *          3   no longer have a key function for class s
705  */
706 
707 @trusted
708 idx_t cv4_struct(Classsym *s,int flags)
709 {   targ_size_t size;
710     debtyp_t* d,dt;
711     uint len;
712     uint nfields,fnamelen;
713     idx_t typidx;
714     type *t;
715     struct_t *st;
716     const(char)* id;
717     uint numidx;
718     uint leaf;
719     uint property;
720     uint attribute;
721     ubyte *p;
722     int refonly;
723     int i;
724     int count;                  // COUNT field in LF_CLASS
725 
726     symbol_debug(s);
727     assert(config.fulltypes >= CV4);
728     st = s.Sstruct;
729     if (st.Sflags & STRanonymous)      // if anonymous class/union
730         return 0;
731 
732     //printf("cv4_struct(%s,%d)\n",s.Sident.ptr,flags);
733     t = s.Stype;
734     //printf("t = %p, Tflags = x%x\n", t, t.Tflags);
735     type_debug(t);
736 
737     // Determine if we should do a reference or a definition
738     refonly = 1;                        // assume reference only
739     if (MARS || t.Tflags & TFsizeunknown || st.Sflags & STRoutdef)
740     {
741         //printf("ref only\n");
742     }
743     else
744     {
745         // We have a definition that we have not put out yet
746         switch (flags)
747         {
748             case 0:                     // reference to s
749                 refonly = 0;
750                 break;
751 
752             case 1:                     // saw def of s
753                 if (!s.Stypidx)        // if not forward referenced
754                     return 0;
755                 break;
756 
757             default:
758                 assert(0);
759         }
760     }
761 
762     if (MARS || refonly)
763     {
764         if (s.Stypidx)                 // if reference already generated
765         {   //assert(s.Stypidx - cgcv.deb_offset < debtyp.length);
766             return s.Stypidx;          // use already existing reference
767         }
768         size = 0;
769         property = 0x80;                // class is forward referenced
770     }
771     else
772     {   size = type_size(t);
773         st.Sflags |= STRoutdef;
774         property = 0;
775     }
776 
777     id = prettyident(s);
778     if (config.fulltypes == CV4)
779     {   numidx = (st.Sflags & STRunion) ? 8 : 12;
780         len = numidx + cv4_numericbytes(cast(uint)size);
781         d = debtyp_alloc(len + cv_stringbytes(id));
782         cv4_storenumeric(d.data.ptr + numidx,cast(uint)size);
783     }
784     else
785     {   numidx = (st.Sflags & STRunion) ? 10 : 18;
786         len = numidx + 4;
787         d = debtyp_alloc(len + cv_stringbytes(id));
788         TOLONG(d.data.ptr + numidx,cast(uint)size);
789     }
790     len += cv_namestring(d.data.ptr + len,id);
791     switch (s.Sclass)
792     {
793         case SC.struct_:
794             leaf = LF_STRUCTURE;
795             if (st.Sflags & STRunion)
796             {   leaf = LF_UNION;
797                 break;
798             }
799             if (st.Sflags & STRclass)
800                 leaf = LF_CLASS;
801             goto L1;
802         L1:
803             if (config.fulltypes == CV4)
804                 TOWORD(d.data.ptr + 8,0);          // dList
805             else
806                 TOLONG(d.data.ptr + 10,0);         // dList
807         if (CPP)
808         {
809         }
810         else
811         {
812             if (config.fulltypes == CV4)
813                 TOWORD(d.data.ptr + 10,0);         // vshape
814             else
815                 TOLONG(d.data.ptr + 14,0);         // vshape
816         }
817             break;
818 
819         default:
820             symbol_print(s);
821             assert(0);
822     }
823     TOWORD(d.data.ptr,leaf);
824 
825     // Assign a number to prevent infinite recursion if a struct member
826     // references the same struct.
827     if (config.fulltypes == CVTDB)
828     {
829     }
830     else
831     {
832         d.length = 0;                  // so cv_debtyp() will allocate new
833         s.Stypidx = cv_debtyp(d);
834         d.length = cast(ushort)len;    // restore length
835     }
836     reset_symbuf.write((&s)[0 .. 1]);
837 
838     if (refonly)                        // if reference only
839     {
840         //printf("refonly\n");
841         TOWORD(d.data.ptr + 2,0);          // count: number of fields is 0
842         if (config.fulltypes == CV4)
843         {   TOWORD(d.data.ptr + 4,0);              // field list is 0
844             TOWORD(d.data.ptr + 6,property);
845         }
846         else
847         {   TOLONG(d.data.ptr + 6,0);              // field list is 0
848             TOWORD(d.data.ptr + 4,property);
849         }
850         return s.Stypidx;
851     }
852 
853     // Compute the number of fields, and the length of the fieldlist record
854     nfields = 0;
855     fnamelen = 2;
856     count = nfields;
857     foreach (sl; ListRange(st.Sfldlst))
858     {   Symbol *sf = list_symbol(sl);
859         targ_size_t offset;
860 
861         symbol_debug(sf);
862         const(char)* sfid = sf.Sident.ptr;
863         switch (sf.Sclass)
864         {
865             case SC.member:
866             case SC.field:
867                 if (CPP && sf == s.Sstruct.Svptr)
868                     fnamelen += ((config.fulltypes == CV4) ? 4 : 8);
869                 else
870                 {   offset = sf.Smemoff;
871                     fnamelen += ((config.fulltypes == CV4) ? 6 : 8) +
872                                 cv4_numericbytes(cast(uint)offset) + cv_stringbytes(sfid);
873                 }
874                 break;
875 
876             default:
877                 continue;
878         }
879         nfields++;
880         count++;
881     }
882 
883     TOWORD(d.data.ptr + 2,count);
884     if (config.fulltypes == CV4)
885         TOWORD(d.data.ptr + 6,property);
886     else
887         TOWORD(d.data.ptr + 4,property);
888 
889     // Generate fieldlist type record
890     dt = debtyp_alloc(fnamelen);
891     p = dt.data.ptr;
892     TOWORD(p,LF_FIELDLIST);
893 
894     // And fill it in
895     p += 2;
896     foreach (sl; ListRange(s.Sstruct.Sfldlst))
897     {   Symbol *sf = list_symbol(sl);
898         targ_size_t offset;
899 
900         symbol_debug(sf);
901         const(char)* sfid = sf.Sident.ptr;
902         switch (sf.Sclass)
903         {
904             case SC.field:
905             {   debtyp_t *db;
906 
907                 if (config.fulltypes == CV4)
908                 {   db = debtyp_alloc(6);
909                     TOWORD(db.data.ptr,LF_BITFIELD);
910                     db.data.ptr[2] = sf.Swidth;
911                     db.data.ptr[3] = sf.Sbit;
912                     TOWORD(db.data.ptr + 4,cv4_symtypidx(sf));
913                 }
914                 else
915                 {   db = debtyp_alloc(8);
916                     TOWORD(db.data.ptr,LF_BITFIELD);
917                     db.data.ptr[6] = sf.Swidth;
918                     db.data.ptr[7] = sf.Sbit;
919                     TOLONG(db.data.ptr + 2,cv4_symtypidx(sf));
920                 }
921                 typidx = cv_debtyp(db);
922                 goto L3;
923             }
924 
925             case SC.member:
926                 typidx = cv4_symtypidx(sf);
927             L3:
928                 offset = sf.Smemoff;
929                 TOWORD(p,LF_MEMBER);
930                 attribute = 0;
931                 if (config.fulltypes == CV4)
932                 {   TOWORD(p + 2,typidx);
933                     TOWORD(p + 4,attribute);
934                     p += 6;
935                 }
936                 else
937                 {   TOLONG(p + 4,typidx);
938                     TOWORD(p + 2,attribute);
939                     p += 8;
940                 }
941                 cv4_storenumeric(p,cast(uint)offset);
942                 p += cv4_numericbytes(cast(uint)offset);
943                 p += cv_namestring(p,sfid);
944                 break;
945 
946             default:
947                 continue;
948         }
949     }
950     //printf("fnamelen = %d, p-dt.data = %d\n",fnamelen,p-dt.data);
951     assert(p - dt.data.ptr == fnamelen);
952     if (config.fulltypes == CV4)
953         TOWORD(d.data.ptr + 4,cv_debtyp(dt));
954     else
955         TOLONG(d.data.ptr + 6,cv_debtyp(dt));
956 
957     return s.Stypidx;
958 }
959 
960 @trusted
961 private uint cv4_fwdenum(type* t)
962 {
963     Symbol* s = t.Ttag;
964 
965     // write a forward reference enum record that is enough for the linker to
966     // fold with original definition from EnumDeclaration
967     uint bty = dttab4[tybasic(t.Tnext.Tty)];
968     const id = prettyident(s);
969     uint len = config.fulltypes == CV8 ? 14 : 10;
970     debtyp_t* d = debtyp_alloc(len + cv_stringbytes(id));
971     switch (config.fulltypes)
972     {
973         case CV8:
974             TOWORD(d.data.ptr, LF_ENUM_V3);
975             TOLONG(d.data.ptr + 2, 0);    // count
976             TOWORD(d.data.ptr + 4, 0x80); // property : forward reference
977             TOLONG(d.data.ptr + 6, bty);  // memtype
978             TOLONG(d.data.ptr + 10, 0);   // fieldlist
979             break;
980 
981         case CV4:
982             TOWORD(d.data.ptr,LF_ENUM);
983             TOWORD(d.data.ptr + 2, 0);    // count
984             TOWORD(d.data.ptr + 4, bty);  // memtype
985             TOLONG(d.data.ptr + 6, 0);    // fieldlist
986             TOWORD(d.data.ptr + 8, 0x80); // property : forward reference
987             break;
988 
989         default:
990             assert(0);
991     }
992     cv_namestring(d.data.ptr + len, id);
993     s.Stypidx = cv_debtyp(d);
994     return s.Stypidx;
995 }
996 
997 /************************************************
998  * Return 'calling convention' type of function.
999  */
1000 
1001 ubyte cv4_callconv(type *t)
1002 {   ubyte call;
1003 
1004     switch (tybasic(t.Tty))
1005     {
1006         case TYffunc:   call = 1;       break;
1007         case TYfpfunc:  call = 3;       break;
1008         case TYf16func: call = 3;       break;
1009         case TYfsfunc:  call = 8;       break;
1010         case TYnsysfunc: call = 9;      break;
1011         case TYfsysfunc: call = 10;     break;
1012         case TYnfunc:   call = 0;       break;
1013         case TYnpfunc:  call = 2;       break;
1014         case TYnsfunc:  call = 7;       break;
1015         case TYifunc:   call = 1;       break;
1016         case TYjfunc:   call = 2;       break;
1017         case TYmfunc:   call = 11;      break;  // this call
1018         default:
1019             assert(0);
1020     }
1021     return call;
1022 }
1023 
1024 /**********************************************
1025  * Return type index for the type of a symbol.
1026  */
1027 private uint cv4_symtypidx(Symbol *s)
1028 {
1029     return cv4_typidx(s.Stype);
1030 }
1031 
1032 /***********************************
1033  * Return CV4 type index for a type.
1034  */
1035 
1036 @trusted
1037 uint cv4_typidx(type *t)
1038 {   uint typidx;
1039     uint u;
1040     uint next;
1041     uint key;
1042     debtyp_t *d;
1043     targ_size_t size;
1044     tym_t tym;
1045     tym_t tycv;
1046     tym_t tymnext;
1047     type *tv;
1048     uint dt;
1049     uint attribute;
1050     ubyte call;
1051 
1052     //printf("cv4_typidx(%p)\n",t);
1053     if (!t)
1054         return dttab4[TYint];           // assume int
1055     type_debug(t);
1056     next = cv4_typidx(t.Tnext);
1057     tycv = t.Tty;
1058     tym = tybasic(tycv);
1059     tycv &= mTYconst | mTYvolatile | mTYimmutable;
1060     attribute = 0;
1061 L1:
1062     dt = dttab4[tym];
1063     switch (tym)
1064     {
1065         case TYllong:
1066             if (t.Tnext)
1067                 goto Ldelegate;
1068             assert(dt);
1069             typidx = dt;
1070             break;
1071 
1072         case TYullong:
1073             if (t.Tnext)
1074                 goto Ldarray;
1075             assert(dt);
1076             typidx = dt;
1077             break;
1078 
1079         case TYvoid:
1080         case TYnoreturn:
1081         case TYchar:
1082         case TYschar:
1083         case TYuchar:
1084         case TYchar16:
1085         case TYshort:
1086         case TYushort:
1087         case TYint:
1088         case TYuint:
1089         case TYulong:
1090         case TYlong:
1091         case TYfloat:
1092         case TYdouble:
1093         case TYdouble_alias:
1094         case TYldouble:
1095         case TYifloat:
1096         case TYidouble:
1097         case TYildouble:
1098         case TYcfloat:
1099         case TYcdouble:
1100         case TYcldouble:
1101         case TYbool:
1102         case TYwchar_t:
1103         case TYdchar:
1104             assert(dt);
1105             typidx = dt;
1106             break;
1107 
1108         case TYnptr:
1109         case TYimmutPtr:
1110         case TYsharePtr:
1111         case TYrestrictPtr:
1112             if (t.Tkey)
1113                 goto Laarray;
1114             goto Lptr;
1115         case TYsptr:
1116         case TYcptr:
1117         case TYfgPtr:
1118         Lptr:
1119                         attribute |= I32 ? 10 : 0;      goto L2;
1120 
1121         case TYfptr:
1122         case TYvptr:    attribute |= I32 ? 11 : 1;      goto L2;
1123         case TYhptr:    attribute |= 2; goto L2;
1124 
1125         L2:
1126             if (config.fulltypes == CV4)
1127             {
1128                 // This is a hack to duplicate bugs in VC, so that the VC
1129                 // debugger will work.
1130                 tymnext = t.Tnext ? t.Tnext.Tty : TYint;
1131                 if (tymnext & (mTYconst | mTYimmutable | mTYvolatile) &&
1132                     !tycv &&
1133                     tyarithmetic(tymnext) &&
1134                     !(attribute & 0xE0)
1135                    )
1136                 {
1137                     typidx = dt | dttab4[tybasic(tymnext)];
1138                     break;
1139                 }
1140             }
1141             if ((next & 0xFF00) == 0 && !(attribute & 0xE0))
1142                 typidx = next | dt;
1143             else
1144             {
1145                 if (tycv & (mTYconst | mTYimmutable))
1146                     attribute |= 0x400;
1147                 if (tycv & mTYvolatile)
1148                     attribute |= 0x200;
1149                 tycv = 0;
1150                 switch (config.fulltypes)
1151                 {
1152                     case CV4:
1153                         d = debtyp_alloc(6);
1154                         TOWORD(d.data.ptr,LF_POINTER);
1155                         TOWORD(d.data.ptr + 2,attribute);
1156                         TOWORD(d.data.ptr + 4,next);
1157                         break;
1158 
1159                     case CV8:
1160                         d = debtyp_alloc(10);
1161                         TOWORD(d.data.ptr,0x1002);
1162                         TOLONG(d.data.ptr + 2,next);
1163                         // see https://github.com/Microsoft/microsoft-pdb/blob/master/include/cvinfo.h#L1514
1164                         // add size and pointer type (PTR_64 or PTR_NEAR32)
1165                         attribute |= (I64 ? (8 << 13) | 0xC : (4 << 13) | 0xA);
1166                         // convert reference to r-value reference to remove & from type display in debugger
1167                         if (attribute & 0x20)
1168                             attribute |= 0x80;
1169                         TOLONG(d.data.ptr + 6,attribute);
1170                         break;
1171 
1172                     default:
1173                         d = debtyp_alloc(10);
1174                         TOWORD(d.data.ptr,LF_POINTER);
1175                         TOLONG(d.data.ptr + 2,attribute);
1176                         TOLONG(d.data.ptr + 6,next);
1177                         break;
1178                 }
1179                 typidx = cv_debtyp(d);
1180             }
1181             break;
1182 
1183         Ldarray:
1184             switch (config.fulltypes)
1185             {
1186                 case CV8:
1187                 {
1188                     typidx = cv8_darray(t, next);
1189                     break;
1190                 }
1191                 case CV4:
1192 static if (1)
1193 {
1194                     d = debtyp_alloc(12);
1195                     TOWORD(d.data.ptr, LF_OEM);
1196                     TOWORD(d.data.ptr + 2, OEM);
1197                     TOWORD(d.data.ptr + 4, 1);     // 1 = dynamic array
1198                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
1199                     TOWORD(d.data.ptr + 8, 0x12);  // index type, T_LONG
1200                     TOWORD(d.data.ptr + 10, next); // element type
1201 }
1202 else
1203 {
1204                     d = debtyp_alloc(6);
1205                     TOWORD(d.data.ptr,LF_DYN_ARRAY);
1206                     TOWORD(d.data.ptr + 2, 0x12);  // T_LONG
1207                     TOWORD(d.data.ptr + 4, next);
1208 }
1209                     typidx = cv_debtyp(d);
1210                     break;
1211 
1212                 default:
1213                     assert(0);
1214             }
1215 
1216             break;
1217 
1218         Laarray:
1219             key = cv4_typidx(t.Tkey);
1220             switch (config.fulltypes)
1221             {
1222                 case CV8:
1223                     typidx = cv8_daarray(t, key, next);
1224                     break;
1225 
1226                 case CV4:
1227 static if (1)
1228 {
1229                     d = debtyp_alloc(12);
1230                     TOWORD(d.data.ptr, LF_OEM);
1231                     TOWORD(d.data.ptr + 2, OEM);
1232                     TOWORD(d.data.ptr + 4, 2);     // 2 = associative array
1233                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
1234                     TOWORD(d.data.ptr + 8, key);   // key type
1235                     TOWORD(d.data.ptr + 10, next); // element type
1236 }
1237 else
1238 {
1239                     d = debtyp_alloc(6);
1240                     TOWORD(d.data.ptr,LF_ASSOC_ARRAY);
1241                     TOWORD(d.data.ptr + 2, key);   // key type
1242                     TOWORD(d.data.ptr + 4, next);  // element type
1243 }
1244                     typidx = cv_debtyp(d);
1245                     break;
1246 
1247                 default:
1248                     assert(0);
1249             }
1250             break;
1251 
1252         Ldelegate:
1253             switch (config.fulltypes)
1254             {
1255                 case CV8:
1256                     typidx = cv8_ddelegate(t, next);
1257                     break;
1258 
1259                 case CV4:
1260                     tv = type_fake(TYnptr);
1261                     tv.Tcount++;
1262                     key = cv4_typidx(tv);
1263                     type_free(tv);
1264 static if (1)
1265 {
1266                     d = debtyp_alloc(12);
1267                     TOWORD(d.data.ptr, LF_OEM);
1268                     TOWORD(d.data.ptr + 2, OEM);
1269                     TOWORD(d.data.ptr + 4, 3);     // 3 = delegate
1270                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
1271                     TOWORD(d.data.ptr + 8, key);   // type of 'this', which is void*
1272                     TOWORD(d.data.ptr + 10, next); // function type
1273 }
1274 else
1275 {
1276                     d = debtyp_alloc(6);
1277                     TOWORD(d.data.ptr,LF_DELEGATE);
1278                     TOWORD(d.data.ptr + 2, key);   // type of 'this', which is void*
1279                     TOWORD(d.data.ptr + 4, next);  // function type
1280 }
1281                     typidx = cv_debtyp(d);
1282                     break;
1283 
1284                 default:
1285                     assert(0);
1286             }
1287             break;
1288 
1289         case TYcent:
1290             if (t.Tnext)
1291                 goto Ldelegate;
1292             assert(dt);
1293             typidx = dt;
1294             break;
1295 
1296         case TYucent:
1297             if (t.Tnext)
1298                 goto Ldarray;
1299             assert(dt);
1300             typidx = dt;
1301             break;
1302 
1303         case TYarray:
1304         {   if (t.Tflags & TFsizeunknown)
1305                 size = 0;               // don't complain if don't know size
1306             else
1307                 size = type_size(t);
1308         Larray:
1309             u = cv4_numericbytes(cast(uint)size);
1310             uint idxtype = I32 ? 0x12 : 0x11;  // T_LONG : T_SHORT
1311             if (I64)
1312                 idxtype = 0x23;                    // T_UQUAD
1313             if(next == dttab4[TYvoid])    // do not encode void[n], this confuses the debugger
1314                 next = dttab4[TYuchar];   // use ubyte instead
1315             switch (config.fulltypes)
1316             {
1317                 case CV8:
1318                     d = debtyp_alloc(10 + u + 1);
1319                     TOWORD(d.data.ptr,0x1503);
1320                     TOLONG(d.data.ptr + 2,next);
1321                     TOLONG(d.data.ptr + 6,idxtype);
1322                     d.data.ptr[10 + u] = 0;             // no name
1323                     cv4_storenumeric(d.data.ptr + 10,cast(uint)size);
1324                     break;
1325 
1326                 case CV4:
1327                     d = debtyp_alloc(6 + u + 1);
1328                     TOWORD(d.data.ptr,LF_ARRAY);
1329                     TOWORD(d.data.ptr + 2,next);
1330                     TOWORD(d.data.ptr + 4,idxtype);
1331                     d.data.ptr[6 + u] = 0;             // no name
1332                     cv4_storenumeric(d.data.ptr + 6,cast(uint)size);
1333                     break;
1334 
1335                 default:
1336                     d = debtyp_alloc(10 + u + 1);
1337                     TOWORD(d.data.ptr,LF_ARRAY);
1338                     TOLONG(d.data.ptr + 2,next);
1339                     TOLONG(d.data.ptr + 6,idxtype);
1340                     d.data.ptr[10 + u] = 0;            // no name
1341                     cv4_storenumeric(d.data.ptr + 10,cast(uint)size);
1342                     break;
1343             }
1344             typidx = cv_debtyp(d);
1345             break;
1346         }
1347 
1348         case TYffunc:
1349         case TYfpfunc:
1350         case TYf16func:
1351         case TYfsfunc:
1352         case TYnsysfunc:
1353         case TYfsysfunc:
1354         case TYnfunc:
1355         case TYnpfunc:
1356         case TYnsfunc:
1357         case TYmfunc:
1358         case TYjfunc:
1359         case TYifunc:
1360         {
1361             param_t *p;
1362             uint nparam;
1363             idx_t paramidx;
1364 
1365             call = cv4_callconv(t);
1366             paramidx = cv4_arglist(t,&nparam);
1367 
1368             // Construct an LF_PROCEDURE
1369             switch (config.fulltypes)
1370             {
1371                 case CV8:
1372                     d = debtyp_alloc(2 + 4 + 1 + 1 + 2 + 4);
1373                     TOWORD(d.data.ptr,LF_PROCEDURE_V2);
1374                     TOLONG(d.data.ptr + 2,next);       // return type
1375                     d.data.ptr[6] = call;
1376                     d.data.ptr[7] = 0;                 // reserved
1377                     TOWORD(d.data.ptr + 8,nparam);
1378                     TOLONG(d.data.ptr + 10,paramidx);
1379                     break;
1380 
1381                 case CV4:
1382                     d = debtyp_alloc(2 + 2 + 1 + 1 + 2 + 2);
1383                     TOWORD(d.data.ptr,LF_PROCEDURE);
1384                     TOWORD(d.data.ptr + 2,next);               // return type
1385                     d.data.ptr[4] = call;
1386                     d.data.ptr[5] = 0;                 // reserved
1387                     TOWORD(d.data.ptr + 6,nparam);
1388                     TOWORD(d.data.ptr + 8,paramidx);
1389                     break;
1390 
1391                 default:
1392                     d = debtyp_alloc(2 + 4 + 1 + 1 + 2 + 4);
1393                     TOWORD(d.data.ptr,LF_PROCEDURE);
1394                     TOLONG(d.data.ptr + 2,next);               // return type
1395                     d.data.ptr[6] = call;
1396                     d.data.ptr[7] = 0;                 // reserved
1397                     TOWORD(d.data.ptr + 8,nparam);
1398                     TOLONG(d.data.ptr + 10,paramidx);
1399                     break;
1400             }
1401 
1402             typidx = cv_debtyp(d);
1403             break;
1404         }
1405 
1406         case TYstruct:
1407         {
1408             if (config.fulltypes == CV8)
1409             {
1410                 typidx = cv8_fwdref(t.Ttag);
1411             }
1412             else
1413             {
1414                 int foo = t.Ttag.Stypidx;
1415                 typidx = cv4_struct(t.Ttag,0);
1416                 //printf("struct '%s' %x %x\n", t.Ttag.Sident.ptr, foo, typidx);
1417             }
1418             break;
1419         }
1420 
1421         case TYenum:
1422             if (CPP)
1423             {
1424             }
1425             else
1426                 typidx = cv4_fwdenum(t);
1427             break;
1428 
1429         case TYref:
1430         case TYnref:
1431             attribute |= 0x20;          // indicate reference pointer
1432             tym = TYnptr;               // convert to C data type
1433             goto L1;                    // and try again
1434 
1435         case TYnullptr:
1436             tym = TYnptr;
1437             next = cv4_typidx(tstypes[TYvoid]);  // rewrite as void*
1438             t = tspvoid;
1439             goto L1;
1440 
1441         // vector types
1442         case TYfloat4:  size = 16; next = dttab4[TYfloat];  goto Larray;
1443         case TYdouble2: size = 16; next = dttab4[TYdouble]; goto Larray;
1444         case TYschar16: size = 16; next = dttab4[TYschar];  goto Larray;
1445         case TYuchar16: size = 16; next = dttab4[TYuchar];  goto Larray;
1446         case TYshort8:  size = 16; next = dttab4[TYshort];  goto Larray;
1447         case TYushort8: size = 16; next = dttab4[TYushort]; goto Larray;
1448         case TYlong4:   size = 16; next = dttab4[TYlong];   goto Larray;
1449         case TYulong4:  size = 16; next = dttab4[TYulong];  goto Larray;
1450         case TYllong2:  size = 16; next = dttab4[TYllong];  goto Larray;
1451         case TYullong2: size = 16; next = dttab4[TYullong]; goto Larray;
1452 
1453         case TYfloat8:   size = 32; next = dttab4[TYfloat];  goto Larray;
1454         case TYdouble4:  size = 32; next = dttab4[TYdouble]; goto Larray;
1455         case TYschar32:  size = 32; next = dttab4[TYschar];  goto Larray;
1456         case TYuchar32:  size = 32; next = dttab4[TYuchar];  goto Larray;
1457         case TYshort16:  size = 32; next = dttab4[TYshort];  goto Larray;
1458         case TYushort16: size = 32; next = dttab4[TYushort]; goto Larray;
1459         case TYlong8:    size = 32; next = dttab4[TYlong];   goto Larray;
1460         case TYulong8:   size = 32; next = dttab4[TYulong];  goto Larray;
1461         case TYllong4:   size = 32; next = dttab4[TYllong];  goto Larray;
1462         case TYullong4:  size = 32; next = dttab4[TYullong]; goto Larray;
1463 
1464         case TYfloat16:  size = 64; next = dttab4[TYfloat];  goto Larray;
1465         case TYdouble8:  size = 64; next = dttab4[TYdouble]; goto Larray;
1466         case TYschar64:  size = 64; next = dttab4[TYschar];  goto Larray;
1467         case TYuchar64:  size = 64; next = dttab4[TYuchar];  goto Larray;
1468         case TYshort32:  size = 64; next = dttab4[TYshort];  goto Larray;
1469         case TYushort32: size = 64; next = dttab4[TYushort]; goto Larray;
1470         case TYlong16:   size = 64; next = dttab4[TYlong];   goto Larray;
1471         case TYulong16:  size = 64; next = dttab4[TYulong];  goto Larray;
1472         case TYllong8:   size = 64; next = dttab4[TYllong];  goto Larray;
1473         case TYullong8:  size = 64; next = dttab4[TYullong]; goto Larray;
1474 
1475         default:
1476             debug
1477             printf("%s\n", tym_str(tym));
1478 
1479             assert(0);
1480     }
1481 
1482     // Add in const and/or volatile modifiers
1483     if (tycv & (mTYconst | mTYimmutable | mTYvolatile))
1484     {   uint modifier;
1485 
1486         modifier = (tycv & (mTYconst | mTYimmutable)) ? 1 : 0;
1487         modifier |= (tycv & mTYvolatile) ? 2 : 0;
1488         switch (config.fulltypes)
1489         {
1490             case CV8:
1491                 d = debtyp_alloc(8);
1492                 TOWORD(d.data.ptr,0x1001);
1493                 TOLONG(d.data.ptr + 2,typidx);
1494                 TOWORD(d.data.ptr + 6,modifier);
1495                 break;
1496 
1497             case CV4:
1498                 d = debtyp_alloc(6);
1499                 TOWORD(d.data.ptr,LF_MODIFIER);
1500                 TOWORD(d.data.ptr + 2,modifier);
1501                 TOWORD(d.data.ptr + 4,typidx);
1502                 break;
1503 
1504             default:
1505                 d = debtyp_alloc(10);
1506                 TOWORD(d.data.ptr,LF_MODIFIER);
1507                 TOLONG(d.data.ptr + 2,modifier);
1508                 TOLONG(d.data.ptr + 6,typidx);
1509                 break;
1510         }
1511         typidx = cv_debtyp(d);
1512     }
1513 
1514     assert(typidx);
1515     return typidx;
1516 }
1517 
1518 /******************************************
1519  * Write out symbol s.
1520  */
1521 
1522 @trusted
1523 private void cv4_outsym(Symbol *s)
1524 {
1525     uint len;
1526     type *t;
1527     uint length;
1528     uint u;
1529     tym_t tym;
1530     const(char)* id;
1531     ubyte *debsym = null;
1532     ubyte[64] buf = void;
1533 
1534     //printf("cv4_outsym(%s)\n",s.Sident.ptr);
1535     symbol_debug(s);
1536     if (s.Sflags & SFLnodebug)
1537         return;
1538     t = s.Stype;
1539     type_debug(t);
1540     tym = tybasic(t.Tty);
1541     if (tyfunc(tym) && s.Sclass != SC.typedef_)
1542     {   int framedatum,targetdatum,fd;
1543         char idfree;
1544         idx_t typidx;
1545 
1546         if (s != funcsym_p)
1547             return;
1548         id = s.prettyIdent ? s.prettyIdent : s.Sident.ptr;
1549         len = cv_stringbytes(id);
1550 
1551         // Length of record
1552         length = 2 + 2 + 4 * 3 + _tysize[TYint] * 4 + 2 + cgcv.sz_idx + 1;
1553         debsym = (length + len <= (buf).sizeof) ? buf.ptr : cast(ubyte *) malloc(length + len);
1554         if (!debsym)
1555             err_nomem();
1556         memset(debsym,0,length + len);
1557 
1558         // Symbol type
1559         u = (s.Sclass == SC.static_) ? S_LPROC16 : S_GPROC16;
1560         if (I32)
1561             u += S_GPROC32 - S_GPROC16;
1562         TOWORD(debsym + 2,u);
1563 
1564         if (config.fulltypes == CV4)
1565         {
1566             // Offsets
1567             if (I32)
1568             {   TOLONG(debsym + 16,cast(uint)s.Ssize);           // proc length
1569                 TOLONG(debsym + 20,cast(uint)startoffset);        // debug start
1570                 TOLONG(debsym + 24,cast(uint)retoffset);          // debug end
1571                 u = 28;                                 // offset to fixup
1572             }
1573             else
1574             {   TOWORD(debsym + 16,cast(uint)s.Ssize);           // proc length
1575                 TOWORD(debsym + 18,cast(uint)startoffset);        // debug start
1576                 TOWORD(debsym + 20,cast(uint)retoffset);          // debug end
1577                 u = 22;                                 // offset to fixup
1578             }
1579             length += cv_namestring(debsym + u + _tysize[TYint] + 2 + cgcv.sz_idx + 1,id);
1580             typidx = cv4_symtypidx(s);
1581             TOIDX(debsym + u + _tysize[TYint] + 2,typidx);     // proc type
1582             debsym[u + _tysize[TYint] + 2 + cgcv.sz_idx] = tyfarfunc(tym) ? 4 : 0;
1583             TOWORD(debsym,length - 2);
1584         }
1585         else
1586         {
1587             // Offsets
1588             if (I32)
1589             {   TOLONG(debsym + 16 + cgcv.sz_idx,cast(uint)s.Ssize);             // proc length
1590                 TOLONG(debsym + 20 + cgcv.sz_idx,cast(uint)startoffset);  // debug start
1591                 TOLONG(debsym + 24 + cgcv.sz_idx,cast(uint)retoffset);            // debug end
1592                 u = 28;                                         // offset to fixup
1593             }
1594             else
1595             {   TOWORD(debsym + 16 + cgcv.sz_idx,cast(uint)s.Ssize);             // proc length
1596                 TOWORD(debsym + 18 + cgcv.sz_idx,cast(uint)startoffset);  // debug start
1597                 TOWORD(debsym + 20 + cgcv.sz_idx,cast(uint)retoffset);            // debug end
1598                 u = 22;                                         // offset to fixup
1599             }
1600             u += cgcv.sz_idx;
1601             length += cv_namestring(debsym + u + _tysize[TYint] + 2 + 1,id);
1602             typidx = cv4_symtypidx(s);
1603             TOIDX(debsym + 16,typidx);                  // proc type
1604             debsym[u + _tysize[TYint] + 2] = tyfarfunc(tym) ? 4 : 0;
1605             TOWORD(debsym,length - 2);
1606         }
1607 
1608         uint soffset = cast(uint)Offset(DEBSYM);
1609         objmod.write_bytes(SegData[DEBSYM],debsym[0 .. length]);
1610 
1611         // Put out fixup for function start offset
1612         objmod.reftoident(DEBSYM,soffset + u,s,0,CFseg | CFoff);
1613     }
1614     else
1615     {   targ_size_t base;
1616         int reg;
1617         uint fd;
1618         uint idx1,idx2;
1619         uint value;
1620         uint fixoff;
1621         idx_t typidx;
1622 
1623         typidx = cv4_typidx(t);
1624         id = s.prettyIdent ? s.prettyIdent : prettyident(s);
1625         len = cast(uint)strlen(id);
1626         debsym = (39 + IDOHD + len <= (buf).sizeof) ? buf.ptr : cast(ubyte *) malloc(39 + IDOHD + len);
1627         if (!debsym)
1628             err_nomem();
1629         switch (s.Sclass)
1630         {
1631             case SC.parameter:
1632             case SC.regpar:
1633                 if (s.Sfl == FLreg)
1634                 {
1635                     s.Sfl = FLpara;
1636                     cv4_outsym(s);
1637                     s.Sfl = FLreg;
1638                     goto case_register;
1639                 }
1640                 base = Para.size - BPoff;    // cancel out add of BPoff
1641                 goto L1;
1642 
1643             case SC.auto_:
1644                 if (s.Sfl == FLreg)
1645                     goto case_register;
1646             case_auto:
1647                 base = Auto.size;
1648             L1:
1649                 if (s.Sscope) // local variables moved into the closure cannot be emitted directly
1650                     goto Lret;
1651                 TOWORD(debsym + 2,I32 ? S_BPREL32 : S_BPREL16);
1652                 if (config.fulltypes == CV4)
1653                 {   TOOFFSET(debsym + 4,s.Soffset + base + BPoff);
1654                     TOIDX(debsym + 4 + _tysize[TYint],typidx);
1655                 }
1656                 else
1657                 {   TOOFFSET(debsym + 4 + cgcv.sz_idx,s.Soffset + base + BPoff);
1658                     TOIDX(debsym + 4,typidx);
1659                 }
1660                 length = 2 + 2 + _tysize[TYint] + cgcv.sz_idx;
1661                 length += cv_namestring(debsym + length,id);
1662                 TOWORD(debsym,length - 2);
1663                 break;
1664 
1665             case SC.bprel:
1666                 base = -BPoff;
1667                 goto L1;
1668 
1669             case SC.fastpar:
1670                 if (s.Sfl != FLreg)
1671                 {   base = Fast.size;
1672                     goto L1;
1673                 }
1674                 goto case_register;
1675 
1676             case SC.register:
1677                 if (s.Sfl != FLreg)
1678                     goto case_auto;
1679                 goto case_register;
1680 
1681             case SC.pseudo:
1682             case_register:
1683                 TOWORD(debsym + 2,S_REGISTER);
1684                 reg = cv_regnum(s);
1685                 TOIDX(debsym + 4,typidx);
1686                 TOWORD(debsym + 4 + cgcv.sz_idx,reg);
1687                 length = 2 * 3 + cgcv.sz_idx;
1688                 length += 1 + cv_namestring(debsym + length,id);
1689                 TOWORD(debsym,length - 2);
1690                 break;
1691 
1692             case SC.extern_:
1693             case SC.comdef:
1694                 // Common blocks have a non-zero Sxtrnnum and an UNKNOWN seg
1695                 if (!(s.Sxtrnnum && s.Sseg == UNKNOWN)) // if it's not really a common block
1696                 {
1697                         goto Lret;
1698                 }
1699                 goto case;
1700             case SC.global:
1701             case SC.comdat:
1702                 u = S_GDATA16;
1703                 goto L2;
1704 
1705             case SC.static_:
1706             case SC.locstat:
1707                 u = S_LDATA16;
1708             L2:
1709                 if (I32)
1710                     u += S_GDATA32 - S_GDATA16;
1711                 TOWORD(debsym + 2,u);
1712                 if (config.fulltypes == CV4)
1713                 {
1714                     fixoff = 4;
1715                     length = 2 + 2 + _tysize[TYint] + 2;
1716                     TOOFFSET(debsym + fixoff,s.Soffset);
1717                     TOWORD(debsym + fixoff + _tysize[TYint],0);
1718                     TOIDX(debsym + length,typidx);
1719                 }
1720                 else
1721                 {
1722                     fixoff = 8;
1723                     length = 2 + 2 + _tysize[TYint] + 2;
1724                     TOOFFSET(debsym + fixoff,s.Soffset);
1725                     TOWORD(debsym + fixoff + _tysize[TYint],0);        // segment
1726                     TOIDX(debsym + 4,typidx);
1727                 }
1728                 length += cgcv.sz_idx;
1729                 length += cv_namestring(debsym + length,id);
1730                 TOWORD(debsym,length - 2);
1731                 assert(length <= 40 + len);
1732 
1733                 if (s.Sseg == UNKNOWN || s.Sclass == SC.comdat) // if common block
1734                 {
1735                     if (config.exe & EX_flat)
1736                     {
1737                         fd = 0x16;
1738                         idx1 = DGROUPIDX;
1739                         idx2 = s.Sxtrnnum;
1740                     }
1741                     else
1742                     {
1743                         fd = 0x26;
1744                         idx1 = idx2 = s.Sxtrnnum;
1745                     }
1746                 }
1747                 else if (s.ty() & (mTYfar | mTYcs))
1748                 {
1749                     fd = 0x04;
1750                     idx1 = idx2 = SegData[s.Sseg].segidx;
1751                 }
1752                 else
1753                 {   fd = 0x14;
1754                     idx1 = DGROUPIDX;
1755                     idx2 = SegData[s.Sseg].segidx;
1756                 }
1757                 /* Because of the linker limitations, the length cannot
1758                  * exceed 0x1000.
1759                  * See optlink\cv\cvhashes.asm
1760                  */
1761                 assert(length <= 0x1000);
1762                 if (idx2 != 0)
1763                 {   uint offset = cast(uint)Offset(DEBSYM);
1764                     objmod.write_bytes(SegData[DEBSYM],debsym[0 .. length]);
1765                     objmod.write_long(DEBSYM,offset + fixoff,cast(uint)s.Soffset,
1766                         cgcv.LCFDpointer + fd,idx1,idx2);
1767                 }
1768                 goto Lret;
1769 
1770 static if (1)
1771 {
1772             case SC.typedef_:
1773                 s.Stypidx = typidx;
1774                 reset_symbuf.write((&s)[0 .. 1]);
1775                 goto L4;
1776 
1777             case SC.struct_:
1778                 if (s.Sstruct.Sflags & STRnotagname)
1779                     goto Lret;
1780                 goto L4;
1781 
1782             case SC.enum_:
1783             L4:
1784                 // Output a 'user-defined type' for the tag name
1785                 TOWORD(debsym + 2,S_UDT);
1786                 TOIDX(debsym + 4,typidx);
1787                 length = 2 + 2 + cgcv.sz_idx;
1788                 length += cv_namestring(debsym + length,id);
1789                 TOWORD(debsym,length - 2);
1790                 list_subtract(&cgcv.list,s);
1791                 break;
1792 
1793             case SC.const_:
1794                 // The only constants are enum members
1795                 value = cast(uint)el_tolongt(s.Svalue);
1796                 TOWORD(debsym + 2,S_CONST);
1797                 TOIDX(debsym + 4,typidx);
1798                 length = 4 + cgcv.sz_idx;
1799                 cv4_storenumeric(debsym + length,value);
1800                 length += cv4_numericbytes(value);
1801                 length += cv_namestring(debsym + length,id);
1802                 TOWORD(debsym,length - 2);
1803                 break;
1804 }
1805             default:
1806                 goto Lret;
1807         }
1808         assert(length <= 40 + len);
1809         objmod.write_bytes(SegData[DEBSYM],debsym[0 .. length]);
1810     }
1811 Lret:
1812     if (debsym != buf.ptr)
1813         free(debsym);
1814 }
1815 
1816 /******************************************
1817  * Write out any deferred symbols.
1818  */
1819 
1820 @trusted
1821 private void cv_outlist()
1822 {
1823     while (cgcv.list)
1824         cv_outsym(cast(Symbol *) list_pop(&cgcv.list));
1825 }
1826 
1827 /******************************************
1828  * Write out symbol table for current function.
1829  */
1830 
1831 @trusted
1832 private void cv4_func(Funcsym *s, ref symtab_t symtab)
1833 {
1834     int endarg;
1835 
1836     cv4_outsym(s);              // put out function symbol
1837     __gshared Funcsym* sfunc;
1838     __gshared int cntOpenBlocks;
1839     sfunc = s;
1840     cntOpenBlocks = 0;
1841 
1842     struct cv4
1843     {
1844     nothrow:
1845         // record for CV record S_BLOCK32
1846         struct block32_data
1847         {
1848             ushort len;
1849             ushort id;
1850             uint pParent;
1851             uint pEnd;
1852             uint length;
1853             uint offset;
1854             ushort seg;
1855             ubyte[2] name;
1856         }
1857 
1858 
1859         static void endArgs()
1860         {
1861             __gshared ushort[2] endargs = [ 2, S_ENDARG ];
1862             objmod.write_bytes(SegData[DEBSYM],endargs[]);
1863         }
1864         static void beginBlock(int offset, int length)
1865         {
1866             if (++cntOpenBlocks >= 255)
1867                 return; // optlink does not like more than 255 scope blocks
1868 
1869             uint soffset = cast(uint)Offset(DEBSYM);
1870             // parent and end to be filled by linker
1871             block32_data block32 = { (block32_data).sizeof - 2, S_BLOCK32, 0, 0, length, 0, 0, [ 0, '\0' ] };
1872             objmod.write_bytes(SegData[DEBSYM], (&block32)[0 .. 1]);
1873             size_t offOffset = cast(char*)&block32.offset - cast(char*)&block32;
1874             objmod.reftoident(DEBSYM, soffset + offOffset, sfunc, offset + sfunc.Soffset, CFseg | CFoff);
1875         }
1876         static void endBlock()
1877         {
1878             if (cntOpenBlocks-- >= 255)
1879                 return; // optlink does not like more than 255 scope blocks
1880 
1881             __gshared ushort[2] endargs = [ 2, S_END ];
1882             objmod.write_bytes(SegData[DEBSYM],endargs[]);
1883         }
1884     }
1885 
1886     varStats_writeSymbolTable(symtab, &cv4_outsym, &cv4.endArgs, &cv4.beginBlock, &cv4.endBlock);
1887 
1888     // Put out function return record
1889     if (1)
1890     {   ubyte[2+2+2+1+1+4] sreturn = void;
1891         ushort flags;
1892         ubyte style;
1893         tym_t ty;
1894         tym_t tyret;
1895         uint u;
1896 
1897         u = 2+2+1;
1898         ty = tybasic(s.ty());
1899 
1900         flags = tyrevfunc(ty) ? 0 : 1;
1901         flags |= typfunc(ty) ? 0 : 2;
1902         TOWORD(sreturn.ptr + 4,flags);
1903 
1904         tyret = tybasic(s.Stype.Tnext.Tty);
1905         switch (tyret)
1906         {
1907             case TYvoid:
1908             default:
1909                 style = 0;
1910                 break;
1911 
1912             case TYbool:
1913             case TYchar:
1914             case TYschar:
1915             case TYuchar:
1916                 sreturn[7] = 1;
1917                 sreturn[8] = 1;         // AL
1918                 goto L1;
1919 
1920             case TYwchar_t:
1921             case TYchar16:
1922             case TYshort:
1923             case TYushort:
1924                 goto case_ax;
1925 
1926             case TYint:
1927             case TYuint:
1928             case TYsptr:
1929             case TYcptr:
1930             case TYnullptr:
1931             case TYnptr:
1932             case TYnref:
1933                 if (I32)
1934                     goto case_eax;
1935                 else
1936                     goto case_ax;
1937 
1938             case TYfloat:
1939             case TYifloat:
1940                 if (config.exe & EX_flat)
1941                     goto case_st0;
1942                 goto case;
1943 
1944             case TYlong:
1945             case TYulong:
1946             case TYdchar:
1947                 if (I32)
1948                     goto case_eax;
1949                 else
1950                     goto case_dxax;
1951 
1952             case TYfptr:
1953             case TYhptr:
1954                 if (I32)
1955                     goto case_edxeax;
1956                 else
1957                     goto case_dxax;
1958 
1959             case TYvptr:
1960                 if (I32)
1961                     goto case_edxebx;
1962                 else
1963                     goto case_dxbx;
1964 
1965             case TYdouble:
1966             case TYidouble:
1967             case TYdouble_alias:
1968                 if (config.exe & EX_flat)
1969                     goto case_st0;
1970                 if (I32)
1971                     goto case_edxeax;
1972                 else
1973                     goto case_axbxcxdx;
1974 
1975             case TYllong:
1976             case TYullong:
1977                 assert(I32);
1978                 goto case_edxeax;
1979 
1980             case TYldouble:
1981             case TYildouble:
1982                 goto case_st0;
1983 
1984             case TYcfloat:
1985             case TYcdouble:
1986             case TYcldouble:
1987                 goto case_st01;
1988 
1989             case_ax:
1990                 sreturn[7] = 1;
1991                 sreturn[8] = 9;         // AX
1992                 goto L1;
1993 
1994             case_eax:
1995                 sreturn[7] = 1;
1996                 sreturn[8] = 17;        // EAX
1997                 goto L1;
1998 
1999 
2000             case_dxax:
2001                 sreturn[7] = 2;
2002                 sreturn[8] = 11;        // DX
2003                 sreturn[9] = 9;         // AX
2004                 goto L1;
2005 
2006             case_dxbx:
2007                 sreturn[7] = 2;
2008                 sreturn[8] = 11;        // DX
2009                 sreturn[9] = 12;        // BX
2010                 goto L1;
2011 
2012             case_axbxcxdx:
2013                 sreturn[7] = 4;
2014                 sreturn[8] = 9;         // AX
2015                 sreturn[9] = 12;        // BX
2016                 sreturn[10] = 10;       // CX
2017                 sreturn[11] = 11;       // DX
2018                 goto L1;
2019 
2020             case_edxeax:
2021                 sreturn[7] = 2;
2022                 sreturn[8] = 19;        // EDX
2023                 sreturn[9] = 17;        // EAX
2024                 goto L1;
2025 
2026             case_edxebx:
2027                 sreturn[7] = 2;
2028                 sreturn[8] = 19;        // EDX
2029                 sreturn[9] = 20;        // EBX
2030                 goto L1;
2031 
2032             case_st0:
2033                 sreturn[7] = 1;
2034                 sreturn[8] = 128;       // ST0
2035                 goto L1;
2036 
2037             case_st01:
2038                 sreturn[7] = 2;
2039                 sreturn[8] = 128;       // ST0 (imaginary)
2040                 sreturn[9] = 129;       // ST1 (real)
2041                 goto L1;
2042 
2043             L1:
2044                 style = 1;
2045                 u += sreturn[7] + 1;
2046                 break;
2047         }
2048         sreturn[6] = style;
2049 
2050         TOWORD(sreturn.ptr,u);
2051         TOWORD(sreturn.ptr + 2,S_RETURN);
2052         objmod.write_bytes(SegData[DEBSYM],sreturn[0 .. u + 2]);
2053     }
2054 
2055     // Put out end scope
2056     {   __gshared ushort[2] endproc = [ 2,S_END ];
2057 
2058         objmod.write_bytes(SegData[DEBSYM],endproc[]);
2059     }
2060 
2061     cv_outlist();
2062 }
2063 
2064 //////////////////////////////////////////////////////////
2065 
2066 /******************************************
2067  * Write out data to .OBJ file.
2068  */
2069 
2070 @trusted
2071 void cv_term()
2072 {
2073     //printf("cv_term(): debtyp.length = %d\n",debtyp.length);
2074 
2075     segidx_t typeseg = objmod.seg_debugT();
2076 
2077     switch (config.fulltypes)
2078     {
2079         case CV4:
2080         case CVSYM:
2081             cv_outlist();
2082             goto case;
2083         case CV8:
2084             objmod.write_bytes(SegData[typeseg],(&cgcv.signature)[0 .. 1]);
2085             if (debtyp.length != 1 || config.fulltypes == CV8)
2086             {
2087                 for (uint u = 0; u < debtyp.length; u++)
2088                 {   debtyp_t *d = debtyp[u];
2089 
2090                     objmod.write_bytes(SegData[typeseg],(cast(void *)d)[uint.sizeof .. uint.sizeof + 2 + d.length]);
2091                     debtyp_free(d);
2092                 }
2093             }
2094             else if (debtyp.length)
2095             {
2096                 debtyp_free(debtyp[0]);
2097             }
2098             break;
2099 
2100 
2101         default:
2102             assert(0);
2103     }
2104 
2105     // debtyp.dtor();  // save for later
2106     vec_free(debtypvec);
2107     debtypvec = null;
2108 }
2109 
2110 /******************************************
2111  * Write out symbol table for current function.
2112  */
2113 
2114 @trusted
2115 void cv_func(Funcsym *s)
2116 {
2117 
2118     //printf("cv_func('%s')\n",s.Sident.ptr);
2119     if (s.Sflags & SFLnodebug)
2120         return;
2121 
2122     switch (config.fulltypes)
2123     {
2124         case CV4:
2125         case CVSYM:
2126         case CVTDB:
2127             cv4_func(s, globsym);
2128             break;
2129 
2130         default:
2131             assert(0);
2132     }
2133 }
2134 
2135 /******************************************
2136  * Write out symbol table for current function.
2137  */
2138 
2139 @trusted
2140 void cv_outsym(Symbol *s)
2141 {
2142     //printf("cv_outsym('%s')\n",s.Sident.ptr);
2143     symbol_debug(s);
2144     if (s.Sflags & SFLnodebug)
2145         return;
2146     switch (config.fulltypes)
2147     {
2148         case CV4:
2149         case CVSYM:
2150         case CVTDB:
2151             cv4_outsym(s);
2152             break;
2153 
2154         case CV8:
2155             cv8_outsym(s);
2156             break;
2157 
2158         default:
2159             assert(0);
2160     }
2161 }
2162 
2163 /******************************************
2164  * Return cv type index for a type.
2165  */
2166 
2167 @trusted
2168 uint cv_typidx(type *t)
2169 {   uint ti;
2170 
2171     //printf("cv_typidx(%p)\n",t);
2172     switch (config.fulltypes)
2173     {
2174         case CV4:
2175         case CVTDB:
2176         case CVSYM:
2177         case CV8:
2178             ti = cv4_typidx(t);
2179             break;
2180 
2181         default:
2182             debug
2183             printf("fulltypes = %d\n",config.fulltypes);
2184 
2185             assert(0);
2186     }
2187     return ti;
2188 }