1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:    Copyright (C) 2012-2021 by The D Language Foundation, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cv8.d, backend/cv8.d)
9  */
10 
11 // This module generates the .debug$S and .debug$T sections for Win64,
12 // which are the MS-Coff symbolic debug info and type debug info sections.
13 
14 module dmd.backend.cv8;
15 
16 version (MARS)
17     version = COMPILE;
18 version (SCPP)
19     version = COMPILE;
20 
21 version (COMPILE)
22 {
23 
24 import core.stdc.stdio;
25 import core.stdc.stdlib;
26 import core.stdc.string;
27 extern (C) nothrow char* getcwd(char*, size_t);
28 
29 import dmd.backend.cc;
30 import dmd.backend.cdef;
31 import dmd.backend.cgcv;
32 import dmd.backend.code;
33 import dmd.backend.code_x86;
34 import dmd.backend.cv4;
35 import dmd.backend.mem;
36 import dmd.backend.el;
37 import dmd.backend.exh;
38 import dmd.backend.global;
39 import dmd.backend.obj;
40 import dmd.backend.oper;
41 import dmd.backend.outbuf;
42 import dmd.backend.rtlsym;
43 import dmd.backend.ty;
44 import dmd.backend.type;
45 import dmd.backend.dvarstats;
46 import dmd.backend.xmm;
47 
48 extern (C++):
49 
50 nothrow:
51 
52 static if (1)
53 {
54 
55 int REGSIZE();
56 
57 // Determine if this Symbol is stored in a COMDAT
58 private bool symbol_iscomdat4(Symbol* s)
59 {
60     version (MARS)
61     {
62         return s.Sclass == SCcomdat ||
63             config.flags2 & CFG2comdat && s.Sclass == SCinline ||
64             config.flags4 & CFG4allcomdat && s.Sclass == SCglobal;
65     }
66     else
67     {
68         return s.Sclass == SCcomdat ||
69             config.flags2 & CFG2comdat && s.Sclass == SCinline ||
70             config.flags4 & CFG4allcomdat && (s.Sclass == SCglobal || s.Sclass == SCstatic);
71     }
72 }
73 
74 
75 // if symbols get longer than 65500 bytes, the linker reports corrupt debug info or exits with
76 // 'fatal error LNK1318: Unexpected PDB error; RPC (23) '(0x000006BA)'
77 enum CV8_MAX_SYMBOL_LENGTH = 0xffd8;
78 
79 // The "F1" section, which is the symbols
80 private __gshared Outbuffer *F1_buf;
81 
82 // The "F2" section, which is the line numbers
83 private __gshared Outbuffer *F2_buf;
84 
85 // The "F3" section, which is global and a string table of source file names.
86 private __gshared Outbuffer *F3_buf;
87 
88 // The "F4" section, which is global and a lists info about source files.
89 private __gshared Outbuffer *F4_buf;
90 
91 /* Fixups that go into F1 section
92  */
93 struct F1_Fixups
94 {
95     Symbol *s;
96     uint offset;
97     uint value;
98 }
99 
100 private __gshared Outbuffer *F1fixup;      // array of F1_Fixups
101 
102 /* Struct in which to collect per-function data, for later emission
103  * into .debug$S.
104  */
105 struct FuncData
106 {
107     Symbol *sfunc;
108     uint section_length;
109     const(char)* srcfilename;
110     uint srcfileoff;
111     uint linepairstart;     // starting byte index of offset/line pairs in linebuf[]
112     uint linepairbytes;     // number of bytes for offset/line pairs
113     uint linepairsegment;   // starting byte index of filename segment for offset/line pairs
114     Outbuffer *f1buf;
115     Outbuffer *f1fixup;
116 }
117 
118 __gshared FuncData currentfuncdata;
119 
120 private __gshared Outbuffer *funcdata;     // array of FuncData's
121 
122 private __gshared Outbuffer *linepair;     // array of offset/line pairs
123 
124 void cv8_writename(Outbuffer *buf, const(char)* name, size_t len)
125 {
126     if(config.flags2 & CFG2gms)
127     {
128         const(char)* start = name;
129         const(char)* cur = strchr(start, '.');
130         const(char)* end = start + len;
131         while(cur != null)
132         {
133             if(cur >= end)
134             {
135                 buf.writen(start, end - start);
136                 return;
137             }
138             buf.writen(start, cur - start);
139             buf.writeByte('@');
140             start = cur + 1;
141             if(start >= end)
142                 return;
143             cur = strchr(start, '.');
144         }
145         buf.writen(start, end - start);
146     }
147     else
148         buf.writen(name, len);
149 }
150 
151 /************************************************
152  * Called at the start of an object file generation.
153  * One source file can generate multiple object files; this starts an object file.
154  * Input:
155  *      filename        source file name
156  */
157 void cv8_initfile(const(char)* filename)
158 {
159     //printf("cv8_initfile()\n");
160 
161     // Recycle buffers; much faster than delete/renew
162 
163     if (!F1_buf)
164     {
165         __gshared Outbuffer f1buf;
166         f1buf.reserve(1024);
167         F1_buf = &f1buf;
168     }
169     F1_buf.reset();
170 
171     if (!F1fixup)
172     {
173         __gshared Outbuffer f1fixupbuf;
174         f1fixupbuf.reserve(1024);
175         F1fixup = &f1fixupbuf;
176     }
177     F1fixup.reset();
178 
179     if (!F2_buf)
180     {
181         __gshared Outbuffer f2buf;
182         f2buf.reserve(1024);
183         F2_buf = &f2buf;
184     }
185     F2_buf.reset();
186 
187     if (!F3_buf)
188     {
189         __gshared Outbuffer f3buf;
190         f3buf.reserve(1024);
191         F3_buf = &f3buf;
192     }
193     F3_buf.reset();
194     F3_buf.writeByte(0);       // first "filename"
195 
196     if (!F4_buf)
197     {
198         __gshared Outbuffer f4buf;
199         f4buf.reserve(1024);
200         F4_buf = &f4buf;
201     }
202     F4_buf.reset();
203 
204     if (!funcdata)
205     {
206         __gshared Outbuffer funcdatabuf;
207         funcdatabuf.reserve(1024);
208         funcdata = &funcdatabuf;
209     }
210     funcdata.reset();
211 
212     if (!linepair)
213     {
214         __gshared Outbuffer linepairbuf;
215         linepairbuf.reserve(1024);
216         linepair = &linepairbuf;
217     }
218     linepair.reset();
219 
220     memset(&currentfuncdata, 0, currentfuncdata.sizeof);
221     currentfuncdata.f1buf = F1_buf;
222     currentfuncdata.f1fixup = F1fixup;
223 
224     cv_init();
225 }
226 
227 void cv8_termfile(const(char)* objfilename)
228 {
229     //printf("cv8_termfile()\n");
230 
231     /* Write out the debug info sections.
232      */
233 
234     int seg = MsCoffObj_seg_debugS();
235 
236     uint value = 4;
237     objmod.bytes(seg,0,4,&value);
238 
239     /* Start with starting symbol in separate "F1" section
240      */
241     Outbuffer buf = Outbuffer(1024);
242     size_t len = strlen(objfilename);
243     buf.write16(cast(int)(2 + 4 + len + 1));
244     buf.write16(S_COMPILAND_V3);
245     buf.write32(0);
246     buf.write(objfilename, cast(uint)(len + 1));
247 
248     // write S_COMPILE record
249     buf.write16(2 + 1 + 1 + 2 + 1 + VERSION.length + 1);
250     buf.write16(S_COMPILE);
251     buf.writeByte(I64 ? 0xD0 : 6); // target machine AMD64 or x86 (Pentium II)
252     buf.writeByte(config.flags2 & CFG2gms ? (CPP != 0) : 'D'); // language index (C/C++/D)
253     buf.write16(0x800 | (config.inline8087 ? 0 : (1<<3)));   // 32-bit, float package
254     buf.writeByte(VERSION.length + 1);
255     buf.writeByte('Z');
256     buf.write(VERSION.ptr, VERSION.length);
257 
258     cv8_writesection(seg, 0xF1, &buf);
259 
260     // Write out "F2" sections
261     uint length = cast(uint)funcdata.length();
262     ubyte *p = funcdata.buf;
263     for (uint u = 0; u < length; u += FuncData.sizeof)
264     {   FuncData *fd = cast(FuncData *)(p + u);
265 
266         F2_buf.reset();
267 
268         F2_buf.write32(cast(uint)fd.sfunc.Soffset);
269         F2_buf.write32(0);
270         F2_buf.write32(fd.section_length);
271         F2_buf.write(linepair.buf + fd.linepairstart, fd.linepairbytes);
272 
273         int f2seg = seg;
274         if (symbol_iscomdat4(fd.sfunc))
275         {
276             f2seg = MsCoffObj_seg_debugS_comdat(fd.sfunc);
277             objmod.bytes(f2seg, 0, 4, &value);
278         }
279 
280         uint offset = cast(uint)SegData[f2seg].SDoffset + 8;
281         cv8_writesection(f2seg, 0xF2, F2_buf);
282         objmod.reftoident(f2seg, offset, fd.sfunc, 0, CFseg | CFoff);
283 
284         if (f2seg != seg && fd.f1buf.length())
285         {
286             // Write out "F1" section
287             const uint f1offset = cast(uint)SegData[f2seg].SDoffset;
288             cv8_writesection(f2seg, 0xF1, fd.f1buf);
289 
290             // Fixups for "F1" section
291             const uint fixupLength = cast(uint)fd.f1fixup.length();
292             ubyte *pfixup = fd.f1fixup.buf;
293             for (uint v = 0; v < fixupLength; v += F1_Fixups.sizeof)
294             {   F1_Fixups *f = cast(F1_Fixups *)(pfixup + v);
295 
296                 objmod.reftoident(f2seg, f1offset + 8 + f.offset, f.s, f.value, CFseg | CFoff);
297             }
298         }
299     }
300 
301     // Write out "F3" section
302     if (F3_buf.length() > 1)
303         cv8_writesection(seg, 0xF3, F3_buf);
304 
305     // Write out "F4" section
306     if (F4_buf.length() > 0)
307         cv8_writesection(seg, 0xF4, F4_buf);
308 
309     if (F1_buf.length())
310     {
311         // Write out "F1" section
312         uint f1offset = cast(uint)SegData[seg].SDoffset;
313         cv8_writesection(seg, 0xF1, F1_buf);
314 
315         // Fixups for "F1" section
316         length = cast(uint)F1fixup.length();
317         p = F1fixup.buf;
318         for (uint u = 0; u < length; u += F1_Fixups.sizeof)
319         {   F1_Fixups *f = cast(F1_Fixups *)(p + u);
320 
321             objmod.reftoident(seg, f1offset + 8 + f.offset, f.s, f.value, CFseg | CFoff);
322         }
323     }
324 
325     // Write out .debug$T section
326     cv_term();
327 }
328 
329 /************************************************
330  * Called at the start of a module.
331  * Note that there can be multiple modules in one object file.
332  * cv8_initfile() must be called first.
333  */
334 void cv8_initmodule(const(char)* filename, const(char)* modulename)
335 {
336     //printf("cv8_initmodule(filename = %s, modulename = %s)\n", filename, modulename);
337 }
338 
339 void cv8_termmodule()
340 {
341     //printf("cv8_termmodule()\n");
342     assert(config.objfmt == OBJ_MSCOFF);
343 }
344 
345 /******************************************
346  * Called at the start of a function.
347  */
348 void cv8_func_start(Symbol *sfunc)
349 {
350     //printf("cv8_func_start(%s)\n", sfunc.Sident);
351     currentfuncdata.sfunc = sfunc;
352     currentfuncdata.section_length = 0;
353     currentfuncdata.srcfilename = null;
354     currentfuncdata.linepairstart += currentfuncdata.linepairbytes;
355     currentfuncdata.linepairbytes = 0;
356     currentfuncdata.f1buf = F1_buf;
357     currentfuncdata.f1fixup = F1fixup;
358     if (symbol_iscomdat4(sfunc))
359     {
360         // This leaks memory
361         currentfuncdata.f1buf = cast(Outbuffer*)mem_calloc(Outbuffer.sizeof);
362         currentfuncdata.f1buf.reserve(128);
363         currentfuncdata.f1fixup = cast(Outbuffer*)mem_calloc(Outbuffer.sizeof);
364         currentfuncdata.f1fixup.reserve(128);
365     }
366 
367     varStats_startFunction();
368 }
369 
370 void cv8_func_term(Symbol *sfunc)
371 {
372     //printf("cv8_func_term(%s)\n", sfunc.Sident);
373 
374     assert(currentfuncdata.sfunc == sfunc);
375     currentfuncdata.section_length = cast(uint)sfunc.Ssize;
376 
377     funcdata.write(&currentfuncdata, currentfuncdata.sizeof);
378 
379     // Write function symbol
380     assert(tyfunc(sfunc.ty()));
381     idx_t typidx;
382     func_t* fn = sfunc.Sfunc;
383     if(fn.Fclass)
384     {
385         // generate member function type info
386         // it would be nicer if this could be in cv4_typidx, but the function info is not available there
387         uint nparam;
388         ubyte call = cv4_callconv(sfunc.Stype);
389         idx_t paramidx = cv4_arglist(sfunc.Stype,&nparam);
390         uint next = cv4_typidx(sfunc.Stype.Tnext);
391 
392         type* classtype = cast(type*)fn.Fclass;
393         uint classidx = cv4_typidx(classtype);
394         type *tp = type_allocn(TYnptr, classtype);
395         uint thisidx = cv4_typidx(tp);  // TODO
396         debtyp_t *d = debtyp_alloc(2 + 4 + 4 + 4 + 1 + 1 + 2 + 4 + 4);
397         TOWORD(d.data.ptr,LF_MFUNCTION_V2);
398         TOLONG(d.data.ptr + 2,next);       // return type
399         TOLONG(d.data.ptr + 6,classidx);   // class type
400         TOLONG(d.data.ptr + 10,thisidx);   // this type
401         d.data.ptr[14] = call;
402         d.data.ptr[15] = 0;                // reserved
403         TOWORD(d.data.ptr + 16,nparam);
404         TOLONG(d.data.ptr + 18,paramidx);
405         TOLONG(d.data.ptr + 22,0);  // this adjust
406         typidx = cv_debtyp(d);
407     }
408     else
409         typidx = cv_typidx(sfunc.Stype);
410 
411     version (MARS)
412         const(char)* id = sfunc.prettyIdent ? sfunc.prettyIdent : prettyident(sfunc);
413     else
414         const(char)* id = prettyident(sfunc);
415     size_t len = strlen(id);
416     if(len > CV8_MAX_SYMBOL_LENGTH)
417         len = CV8_MAX_SYMBOL_LENGTH;
418     /*
419      *  2       length (not including these 2 bytes)
420      *  2       S_GPROC_V3
421      *  4       parent
422      *  4       pend
423      *  4       pnext
424      *  4       size of function
425      *  4       size of function prolog
426      *  4       offset to function epilog
427      *  4       type index
428      *  6       seg:offset of function start
429      *  1       flags
430      *  n       0 terminated name string
431      */
432     Outbuffer *buf = currentfuncdata.f1buf;
433     buf.reserve(cast(uint)(2 + 2 + 4 * 7 + 6 + 1 + len + 1));
434     buf.write16n(cast(int)(2 + 4 * 7 + 6 + 1 + len + 1));
435     buf.write16n(sfunc.Sclass == SCstatic ? S_LPROC_V3 : S_GPROC_V3);
436     buf.write32(0);            // parent
437     buf.write32(0);            // pend
438     buf.write32(0);            // pnext
439     buf.write32(cast(uint)currentfuncdata.section_length); // size of function
440     buf.write32(cast(uint)startoffset);                    // size of prolog
441     buf.write32(cast(uint)retoffset);                      // offset to epilog
442     buf.write32(typidx);
443 
444     F1_Fixups f1f;
445     f1f.s = sfunc;
446     f1f.offset = cast(uint)buf.length();
447     f1f.value = 0;
448     currentfuncdata.f1fixup.write(&f1f, f1f.sizeof);
449     buf.write32(0);
450     buf.write16n(0);
451 
452     buf.writeByte(0);
453     buf.writen(id, len);
454     buf.writeByte(0);
455 
456     struct cv8
457     {
458     nothrow:
459         // record for CV record S_BLOCK_V3
460         struct block_v3_data
461         {
462             ushort len;
463             ushort id;
464             uint pParent;
465             uint pEnd;
466             uint length;
467             uint offset;
468             ushort seg;
469             ubyte[1] name;
470         }
471 
472         extern (C++) static void endArgs()
473         {
474             Outbuffer *buf = currentfuncdata.f1buf;
475             buf.write16(2);
476             buf.write16(S_ENDARG);
477         }
478         extern (C++) static void beginBlock(int offset, int length)
479         {
480             Outbuffer *buf = currentfuncdata.f1buf;
481             uint soffset = cast(uint)buf.length();
482             // parent and end to be filled by linker
483             block_v3_data block32 = { block_v3_data.sizeof - 2, S_BLOCK_V3, 0, 0, length, offset, 0, [ 0 ] };
484             buf.write(&block32, block32.sizeof);
485             size_t offOffset = cast(char*)&block32.offset - cast(char*)&block32;
486 
487             F1_Fixups f1f;
488             f1f.s = currentfuncdata.sfunc;
489             f1f.offset = cast(uint)(soffset + offOffset);
490             f1f.value = offset;
491             currentfuncdata.f1fixup.write(&f1f, f1f.sizeof);
492         }
493         extern (C++) static void endBlock()
494         {
495             Outbuffer *buf = currentfuncdata.f1buf;
496             buf.write16(2);
497             buf.write16(S_END);
498         }
499     }
500     varStats_writeSymbolTable(globsym, &cv8_outsym, &cv8.endArgs, &cv8.beginBlock, &cv8.endBlock);
501 
502     /* Put out function return record S_RETURN
503      * (VC doesn't, so we won't bother, either.)
504      */
505 
506     // Write function end symbol
507     buf.write16(2);
508     buf.write16(S_END);
509 
510     currentfuncdata.f1buf = F1_buf;
511     currentfuncdata.f1fixup = F1fixup;
512 }
513 
514 /**********************************************
515  */
516 
517 void cv8_linnum(Srcpos srcpos, uint offset)
518 {
519     version (MARS)
520         const sfilename = srcpos.Sfilename;
521     else
522         const sfilename = srcpos_name(srcpos);
523     //printf("cv8_linnum(file = %s, line = %d, offset = x%x)\n", sfilename, (int)srcpos.Slinnum, (uint)offset);
524 
525     if (!sfilename)
526         return;
527 
528     varStats_recordLineOffset(srcpos, offset);
529 
530     __gshared uint lastoffset;
531     __gshared uint lastlinnum;
532 
533     if (!currentfuncdata.srcfilename ||
534         (currentfuncdata.srcfilename != sfilename && strcmp(currentfuncdata.srcfilename, sfilename)))
535     {
536         currentfuncdata.srcfilename = sfilename;
537         uint srcfileoff = cv8_addfile(sfilename);
538 
539         // new file segment
540         currentfuncdata.linepairsegment = currentfuncdata.linepairstart + currentfuncdata.linepairbytes;
541 
542         linepair.write32(srcfileoff);
543         linepair.write32(0); // reserve space for length information
544         linepair.write32(12);
545         currentfuncdata.linepairbytes += 12;
546     }
547     else if (offset <= lastoffset || srcpos.Slinnum == lastlinnum)
548         return; // avoid multiple entries for the same offset
549 
550     lastoffset = offset;
551     lastlinnum = srcpos.Slinnum;
552     linepair.write32(offset);
553     linepair.write32(srcpos.Slinnum | 0x80000000); // mark as statement, not expression
554 
555     currentfuncdata.linepairbytes += 8;
556 
557     // update segment length
558     auto segmentbytes = currentfuncdata.linepairstart + currentfuncdata.linepairbytes - currentfuncdata.linepairsegment;
559     auto segmentheader = cast(uint*)(linepair.buf + currentfuncdata.linepairsegment);
560     segmentheader[1] = (segmentbytes - 12) / 8;
561     segmentheader[2] = segmentbytes;
562 }
563 
564 /**********************************************
565  * Add source file, if it isn't already there.
566  * Return offset into F4.
567  */
568 
569 uint cv8_addfile(const(char)* filename)
570 {
571     //printf("cv8_addfile('%s')\n", filename);
572 
573     /* The algorithms here use a linear search. This is acceptable only
574      * because we expect only 1 or 2 files to appear.
575      * Unlike C, there won't be lots of .h source files to be accounted for.
576      */
577 
578     uint length = cast(uint)F3_buf.length();
579     ubyte *p = F3_buf.buf;
580     size_t len = strlen(filename);
581 
582     // ensure the filename is absolute to help the debugger to find the source
583     // without having to know the working directory during compilation
584     __gshared char[260] cwd = 0;
585     __gshared uint cwdlen;
586     bool abs = (*filename == '\\') ||
587                (*filename == '/')  ||
588                (*filename && filename[1] == ':');
589 
590     if (!abs && cwd[0] == 0)
591     {
592         if (getcwd(cwd.ptr, cwd.sizeof))
593         {
594             cwdlen = cast(uint)strlen(cwd.ptr);
595             if(cwd[cwdlen - 1] != '\\' && cwd[cwdlen - 1] != '/')
596                 cwd[cwdlen++] = '\\';
597         }
598     }
599     uint off = 1;
600     while (off + len < length)
601     {
602         if (!abs)
603         {
604             if (memcmp(p + off, cwd.ptr, cwdlen) == 0 &&
605                 memcmp(p + off + cwdlen, filename, len + 1) == 0)
606                 goto L1;
607         }
608         else if (memcmp(p + off, filename, len + 1) == 0)
609         {   // Already there
610             //printf("\talready there at %x\n", off);
611             goto L1;
612         }
613         off += strlen(cast(const(char)* )(p + off)) + 1;
614     }
615     off = length;
616     // Add it
617     if(!abs)
618         F3_buf.write(cwd.ptr, cwdlen);
619     F3_buf.write(filename, cast(uint)(len + 1));
620 
621 L1:
622     // off is the offset of the filename in F3.
623     // Find it in F4.
624 
625     length = cast(uint)F4_buf.length();
626     p = F4_buf.buf;
627 
628     uint u = 0;
629     while (u + 8 <= length)
630     {
631         //printf("\t%x\n", *(uint *)(p + u));
632         if (off == *cast(uint *)(p + u))
633         {
634             //printf("\tfound %x\n", u);
635             return u;
636         }
637         u += 4;
638         ushort type = *cast(ushort *)(p + u);
639         u += 2;
640         if (type == 0x0110)
641             u += 16;            // MD5 checksum
642         u += 2;
643     }
644 
645     // Not there. Add it.
646     F4_buf.write32(off);
647 
648     /* Write 10 01 [MD5 checksum]
649      *   or
650      * 00 00
651      */
652     F4_buf.write16(0);
653 
654     // 2 bytes of pad
655     F4_buf.write16(0);
656 
657     //printf("\tadded %x\n", length);
658     return length;
659 }
660 
661 void cv8_writesection(int seg, uint type, Outbuffer *buf)
662 {
663     /* Write out as:
664      *  bytes   desc
665      *  -------+----
666      *  4       type
667      *  4       length
668      *  length  data
669      *  pad     pad to 4 byte boundary
670      */
671     uint off = cast(uint)SegData[seg].SDoffset;
672     objmod.bytes(seg,off,4,&type);
673     uint length = cast(uint)buf.length();
674     objmod.bytes(seg,off+4,4,&length);
675     objmod.bytes(seg,off+8,length,buf.buf);
676     // Align to 4
677     uint pad = ((length + 3) & ~3) - length;
678     objmod.lidata(seg,off+8+length,pad);
679 }
680 
681 void cv8_outsym(Symbol *s)
682 {
683     //printf("cv8_outsym(s = '%s')\n", s.Sident);
684     //type_print(s.Stype);
685     //symbol_print(s);
686     if (s.Sflags & SFLnodebug)
687         return;
688 
689     idx_t typidx = cv_typidx(s.Stype);
690     //printf("typidx = %x\n", typidx);
691     version (MARS)
692         const(char)* id = s.prettyIdent ? s.prettyIdent : prettyident(s);
693     else
694         const(char)* id = prettyident(s);
695     size_t len = strlen(id);
696 
697     if(len > CV8_MAX_SYMBOL_LENGTH)
698         len = CV8_MAX_SYMBOL_LENGTH;
699 
700     F1_Fixups f1f;
701     f1f.value = 0;
702     Outbuffer *buf = currentfuncdata.f1buf;
703 
704     uint sr;
705     uint base;
706     switch (s.Sclass)
707     {
708         case SCparameter:
709         case SCregpar:
710         case SCshadowreg:
711             if (s.Sfl == FLreg)
712             {
713                 s.Sfl = FLpara;
714                 cv8_outsym(s);
715                 s.Sfl = FLreg;
716                 goto case_register;
717             }
718             base = cast(uint)(Para.size - BPoff);    // cancel out add of BPoff
719             goto L1;
720 
721         case SCauto:
722             if (s.Sfl == FLreg)
723                 goto case_register;
724         case_auto:
725             base = cast(uint)Auto.size;
726         L1:
727             if (s.Sscope) // local variables moved into the closure cannot be emitted directly
728                 break;
729 static if (1)
730 {
731             // Register relative addressing
732             buf.reserve(cast(uint)(2 + 2 + 4 + 4 + 2 + len + 1));
733             buf.write16n(cast(uint)(2 + 4 + 4 + 2 + len + 1));
734             buf.write16n(0x1111);
735             buf.write32(cast(uint)(s.Soffset + base + BPoff));
736             buf.write32(typidx);
737             buf.write16n(I64 ? 334 : 22);       // relative to RBP/EBP
738             cv8_writename(buf, id, len);
739             buf.writeByte(0);
740 }
741 else
742 {
743             // This is supposed to work, implicit BP relative addressing, but it does not
744             buf.reserve(2 + 2 + 4 + 4 + len + 1);
745             buf.write16n( 2 + 4 + 4 + len + 1);
746             buf.write16n(S_BPREL_V3);
747             buf.write32(s.Soffset + base + BPoff);
748             buf.write32(typidx);
749             cv8_writename(buf, id, len);
750             buf.writeByte(0);
751 }
752             break;
753 
754         case SCbprel:
755             base = -BPoff;
756             goto L1;
757 
758         case SCfastpar:
759             if (s.Sfl != FLreg)
760             {   base = cast(uint)Fast.size;
761                 goto L1;
762             }
763             goto L2;
764 
765         case SCregister:
766             if (s.Sfl != FLreg)
767                 goto case_auto;
768             goto case;
769 
770         case SCpseudo:
771         case_register:
772         L2:
773             buf.reserve(cast(uint)(2 + 2 + 4 + 2 + len + 1));
774             buf.write16n(cast(uint)(2 + 4 + 2 + len + 1));
775             buf.write16n(S_REGISTER_V3);
776             buf.write32(typidx);
777             buf.write16n(cv8_regnum(s));
778             cv8_writename(buf, id, len);
779             buf.writeByte(0);
780             break;
781 
782         case SCextern:
783             break;
784 
785         case SCstatic:
786         case SClocstat:
787             sr = S_LDATA_V3;
788             goto Ldata;
789 
790         case SCglobal:
791         case SCcomdat:
792         case SCcomdef:
793             sr = S_GDATA_V3;
794         Ldata:
795             /*
796              *  2       length (not including these 2 bytes)
797              *  2       S_GDATA_V2
798              *  4       typidx
799              *  6       ref to symbol
800              *  n       0 terminated name string
801              */
802             if (s.ty() & mTYthread)            // thread local storage
803                 sr = (sr == S_GDATA_V3) ? 0x1113 : 0x1112;
804 
805             buf.reserve(cast(uint)(2 + 2 + 4 + 6 + len + 1));
806             buf.write16n(cast(uint)(2 + 4 + 6 + len + 1));
807             buf.write16n(sr);
808             buf.write32(typidx);
809 
810             f1f.s = s;
811             f1f.offset = cast(uint)buf.length();
812             F1fixup.write(&f1f, f1f.sizeof);
813             buf.write32(0);
814             buf.write16n(0);
815 
816             cv8_writename(buf, id, len);
817             buf.writeByte(0);
818             break;
819 
820         default:
821             break;
822     }
823 }
824 
825 
826 /*******************************************
827  * Put out a name for a user defined type.
828  * Input:
829  *      id      the name
830  *      typidx  and its type
831  */
832 void cv8_udt(const(char)* id, idx_t typidx)
833 {
834     //printf("cv8_udt('%s', %x)\n", id, typidx);
835     Outbuffer *buf = currentfuncdata.f1buf;
836     size_t len = strlen(id);
837 
838     if (len > CV8_MAX_SYMBOL_LENGTH)
839         len = CV8_MAX_SYMBOL_LENGTH;
840     buf.reserve(cast(uint)(2 + 2 + 4 + len + 1));
841     buf.write16n(cast(uint)(2 + 4 + len + 1));
842     buf.write16n(S_UDT_V3);
843     buf.write32(typidx);
844     cv8_writename(buf, id, len);
845     buf.writeByte(0);
846 }
847 
848 /*********************************************
849  * Get Codeview register number for symbol s.
850  */
851 int cv8_regnum(Symbol *s)
852 {
853     int reg = s.Sreglsw;
854     assert(s.Sfl == FLreg);
855     if ((1 << reg) & XMMREGS)
856         return reg - XMM0 + 154;
857     switch (type_size(s.Stype))
858     {
859         case 1:
860             if (reg < 4)
861                 reg += 1;
862             else if (reg >= 4 && reg < 8)
863                 reg += 324 - 4;
864             else
865                 reg += 344 - 4;
866             break;
867 
868         case 2:
869             if (reg < 8)
870                 reg += 9;
871             else
872                 reg += 352 - 8;
873             break;
874 
875         case 4:
876             if (reg < 8)
877                 reg += 17;
878             else
879                 reg += 360 - 8;
880             break;
881 
882         case 8:
883             reg += 328;
884             break;
885 
886         default:
887             reg = 0;
888             break;
889     }
890     return reg;
891 }
892 
893 /***************************************
894  * Put out a forward ref for structs, unions, and classes.
895  * Only put out the real definitions with toDebug().
896  */
897 idx_t cv8_fwdref(Symbol *s)
898 {
899     assert(config.fulltypes == CV8);
900 //    if (s.Stypidx && !global.params.multiobj)
901 //      return s.Stypidx;
902     struct_t *st = s.Sstruct;
903     uint leaf;
904     uint numidx;
905     if (st.Sflags & STRunion)
906     {
907         leaf = LF_UNION_V3;
908         numidx = 10;
909     }
910     else if (st.Sflags & STRclass)
911     {
912         leaf = LF_CLASS_V3;
913         numidx = 18;
914     }
915     else
916     {
917         leaf = LF_STRUCTURE_V3;
918         numidx = 18;
919     }
920     uint len = numidx + cv4_numericbytes(0);
921     int idlen = cast(int)strlen(s.Sident.ptr);
922 
923     if (idlen > CV8_MAX_SYMBOL_LENGTH)
924         idlen = CV8_MAX_SYMBOL_LENGTH;
925 
926     debtyp_t *d = debtyp_alloc(len + idlen + 1);
927     TOWORD(d.data.ptr, leaf);
928     TOWORD(d.data.ptr + 2, 0);     // number of fields
929     TOWORD(d.data.ptr + 4, 0x80);  // property
930     TOLONG(d.data.ptr + 6, 0);     // field list
931     if (leaf == LF_CLASS_V3 || leaf == LF_STRUCTURE_V3)
932     {
933         TOLONG(d.data.ptr + 10, 0);        // dList
934         TOLONG(d.data.ptr + 14, 0);        // vshape
935     }
936     cv4_storenumeric(d.data.ptr + numidx, 0);
937     cv_namestring(d.data.ptr + len, s.Sident.ptr, idlen);
938     d.data.ptr[len + idlen] = 0;
939     idx_t typidx = cv_debtyp(d);
940     s.Stypidx = typidx;
941 
942     return typidx;
943 }
944 
945 /****************************************
946  * Return type index for a darray of type E[]
947  * Input:
948  *      t       darray type
949  *      etypidx type index for E
950  */
951 idx_t cv8_darray(type *t, idx_t etypidx)
952 {
953     //printf("cv8_darray(etypidx = %x)\n", etypidx);
954     /* Put out a struct:
955      *    struct dArray {
956      *      size_t length;
957      *      E* ptr;
958      *    }
959      */
960 
961 static if (0)
962 {
963     d = debtyp_alloc(18);
964     TOWORD(d.data.ptr, 0x100F);
965     TOWORD(d.data.ptr + 2, OEM);
966     TOWORD(d.data.ptr + 4, 1);     // 1 = dynamic array
967     TOLONG(d.data.ptr + 6, 2);     // count of type indices to follow
968     TOLONG(d.data.ptr + 10, 0x23); // index type, T_UQUAD
969     TOLONG(d.data.ptr + 14, next); // element type
970     return cv_debtyp(d);
971 }
972 
973     type *tp = type_pointer(t.Tnext);
974     idx_t ptridx = cv4_typidx(tp);
975     type_free(tp);
976 
977     __gshared const ubyte[38] fl =
978     [
979         0x03, 0x12,             // LF_FIELDLIST_V2
980         0x0d, 0x15,             // LF_MEMBER_V3
981         0x03, 0x00,             // attribute
982         0x23, 0x00, 0x00, 0x00, // size_t
983         0x00, 0x00,             // offset
984         'l', 'e', 'n', 'g', 't', 'h', 0x00,
985         0xf3, 0xf2, 0xf1,       // align to 4-byte including length word before data
986         0x0d, 0x15,
987         0x03, 0x00,
988         0x00, 0x00, 0x00, 0x00, // etypidx
989         0x08, 0x00,
990         'p', 't', 'r', 0x00,
991         0xf2, 0xf1,
992     ];
993 
994     debtyp_t *f = debtyp_alloc(fl.sizeof);
995     memcpy(f.data.ptr,fl.ptr,fl.sizeof);
996     TOLONG(f.data.ptr + 6, I64 ? 0x23 : 0x22); // size_t
997     TOLONG(f.data.ptr + 26, ptridx);
998     TOWORD(f.data.ptr + 30, _tysize[TYnptr]);
999     idx_t fieldlist = cv_debtyp(f);
1000 
1001     const(char)* id;
1002     switch (t.Tnext.Tty)
1003     {
1004         case mTYimmutable | TYchar:
1005             id = "string";
1006             break;
1007 
1008         case mTYimmutable | TYwchar_t:
1009             id = "wstring";
1010             break;
1011 
1012         case mTYimmutable | TYdchar:
1013             id = "dstring";
1014             break;
1015 
1016         default:
1017             id = t.Tident ? t.Tident : "dArray";
1018             break;
1019     }
1020 
1021     int idlen = cast(int)strlen(id);
1022 
1023     if (idlen > CV8_MAX_SYMBOL_LENGTH)
1024         idlen = CV8_MAX_SYMBOL_LENGTH;
1025 
1026     debtyp_t *d = debtyp_alloc(20 + idlen + 1);
1027     TOWORD(d.data.ptr, LF_STRUCTURE_V3);
1028     TOWORD(d.data.ptr + 2, 2);     // count
1029     TOWORD(d.data.ptr + 4, 0);     // property
1030     TOLONG(d.data.ptr + 6, fieldlist);
1031     TOLONG(d.data.ptr + 10, 0);    // dList
1032     TOLONG(d.data.ptr + 14, 0);    // vtshape
1033     TOWORD(d.data.ptr + 18, 2 * _tysize[TYnptr]);   // size
1034     cv_namestring(d.data.ptr + 20, id, idlen);
1035     d.data.ptr[20 + idlen] = 0;
1036 
1037     idx_t top = cv_numdebtypes();
1038     idx_t debidx = cv_debtyp(d);
1039     if(top != cv_numdebtypes())
1040         cv8_udt(id, debidx);
1041 
1042     return debidx;
1043 }
1044 
1045 /****************************************
1046  * Return type index for a delegate
1047  * Input:
1048  *      t          delegate type
1049  *      functypidx type index for pointer to function
1050  */
1051 idx_t cv8_ddelegate(type *t, idx_t functypidx)
1052 {
1053     //printf("cv8_ddelegate(functypidx = %x)\n", functypidx);
1054     /* Put out a struct:
1055      *    struct dDelegate {
1056      *      void* ptr;
1057      *      function* funcptr;
1058      *    }
1059      */
1060 
1061     type *tv = type_fake(TYnptr);
1062     tv.Tcount++;
1063     idx_t pvidx = cv4_typidx(tv);
1064     type_free(tv);
1065 
1066     type *tp = type_pointer(t.Tnext);
1067     idx_t ptridx = cv4_typidx(tp);
1068     type_free(tp);
1069 
1070 static if (0)
1071 {
1072     debtyp_t *d = debtyp_alloc(18);
1073     TOWORD(d.data.ptr, 0x100F);
1074     TOWORD(d.data.ptr + 2, OEM);
1075     TOWORD(d.data.ptr + 4, 3);     // 3 = delegate
1076     TOLONG(d.data.ptr + 6, 2);     // count of type indices to follow
1077     TOLONG(d.data.ptr + 10, key);  // void* type
1078     TOLONG(d.data.ptr + 14, functypidx); // function type
1079 }
1080 else
1081 {
1082     __gshared const ubyte[38] fl =
1083     [
1084         0x03, 0x12,             // LF_FIELDLIST_V2
1085         0x0d, 0x15,             // LF_MEMBER_V3
1086         0x03, 0x00,             // attribute
1087         0x00, 0x00, 0x00, 0x00, // void*
1088         0x00, 0x00,             // offset
1089         'p','t','r',0,          // "ptr"
1090         0xf2, 0xf1,             // align to 4-byte including length word before data
1091         0x0d, 0x15,
1092         0x03, 0x00,
1093         0x00, 0x00, 0x00, 0x00, // ptrtypidx
1094         0x08, 0x00,
1095         'f', 'u','n','c','p','t','r', 0,        // "funcptr"
1096         0xf2, 0xf1,
1097     ];
1098 
1099     debtyp_t *f = debtyp_alloc(fl.sizeof);
1100     memcpy(f.data.ptr,fl.ptr,fl.sizeof);
1101     TOLONG(f.data.ptr + 6, pvidx);
1102     TOLONG(f.data.ptr + 22, ptridx);
1103     TOWORD(f.data.ptr + 26, _tysize[TYnptr]);
1104     idx_t fieldlist = cv_debtyp(f);
1105 
1106     const(char)* id = "dDelegate";
1107     int idlen = cast(int)strlen(id);
1108     if (idlen > CV8_MAX_SYMBOL_LENGTH)
1109         idlen = CV8_MAX_SYMBOL_LENGTH;
1110 
1111     debtyp_t *d = debtyp_alloc(20 + idlen + 1);
1112     TOWORD(d.data.ptr, LF_STRUCTURE_V3);
1113     TOWORD(d.data.ptr + 2, 2);     // count
1114     TOWORD(d.data.ptr + 4, 0);     // property
1115     TOLONG(d.data.ptr + 6, fieldlist);
1116     TOLONG(d.data.ptr + 10, 0);    // dList
1117     TOLONG(d.data.ptr + 14, 0);    // vtshape
1118     TOWORD(d.data.ptr + 18, 2 * _tysize[TYnptr]);   // size
1119     memcpy(d.data.ptr + 20, id, idlen);
1120     d.data.ptr[20 + idlen] = 0;
1121 }
1122     return cv_debtyp(d);
1123 }
1124 
1125 /****************************************
1126  * Return type index for a aarray of type Value[Key]
1127  * Input:
1128  *      t          associative array type
1129  *      keyidx     key type
1130  *      validx     value type
1131  */
1132 idx_t cv8_daarray(type *t, idx_t keyidx, idx_t validx)
1133 {
1134     //printf("cv8_daarray(keyidx = %x, validx = %x)\n", keyidx, validx);
1135     /* Put out a struct:
1136      *    struct dAssocArray {
1137      *      void* ptr;
1138      *      typedef key-type __key_t;
1139      *      typedef val-type __val_t;
1140      *    }
1141      */
1142 
1143 static if (0)
1144 {
1145     debtyp_t *d = debtyp_alloc(18);
1146     TOWORD(d.data.ptr, 0x100F);
1147     TOWORD(d.data.ptr + 2, OEM);
1148     TOWORD(d.data.ptr + 4, 2);     // 2 = associative array
1149     TOLONG(d.data.ptr + 6, 2);     // count of type indices to follow
1150     TOLONG(d.data.ptr + 10, keyidx);  // key type
1151     TOLONG(d.data.ptr + 14, validx);  // element type
1152 }
1153 else
1154 {
1155     type *tv = type_fake(TYnptr);
1156     tv.Tcount++;
1157     idx_t pvidx = cv4_typidx(tv);
1158     type_free(tv);
1159 
1160     __gshared const ubyte[50] fl =
1161     [
1162         0x03, 0x12,             // LF_FIELDLIST_V2
1163         0x0d, 0x15,             // LF_MEMBER_V3
1164         0x03, 0x00,             // attribute
1165         0x00, 0x00, 0x00, 0x00, // void*
1166         0x00, 0x00,             // offset
1167         'p','t','r',0,          // "ptr"
1168         0xf2, 0xf1,             // align to 4-byte including field id
1169         // offset 18
1170         0x10, 0x15,             // LF_NESTTYPE_V3
1171         0x00, 0x00,             // padding
1172         0x00, 0x00, 0x00, 0x00, // key type
1173         '_','_','k','e','y','_','t',0,  // "__key_t"
1174         // offset 34
1175         0x10, 0x15,             // LF_NESTTYPE_V3
1176         0x00, 0x00,             // padding
1177         0x00, 0x00, 0x00, 0x00, // value type
1178         '_','_','v','a','l','_','t',0,  // "__val_t"
1179     ];
1180 
1181     debtyp_t *f = debtyp_alloc(fl.sizeof);
1182     memcpy(f.data.ptr,fl.ptr,fl.sizeof);
1183     TOLONG(f.data.ptr + 6, pvidx);
1184     TOLONG(f.data.ptr + 22, keyidx);
1185     TOLONG(f.data.ptr + 38, validx);
1186     idx_t fieldlist = cv_debtyp(f);
1187 
1188     const(char)* id = t.Tident ? t.Tident : "dAssocArray";
1189     int idlen = cast(int)strlen(id);
1190     if (idlen > CV8_MAX_SYMBOL_LENGTH)
1191         idlen = CV8_MAX_SYMBOL_LENGTH;
1192 
1193     debtyp_t *d = debtyp_alloc(20 + idlen + 1);
1194     TOWORD(d.data.ptr, LF_STRUCTURE_V3);
1195     TOWORD(d.data.ptr + 2, 1);     // count
1196     TOWORD(d.data.ptr + 4, 0);     // property
1197     TOLONG(d.data.ptr + 6, fieldlist);
1198     TOLONG(d.data.ptr + 10, 0);    // dList
1199     TOLONG(d.data.ptr + 14, 0);    // vtshape
1200     TOWORD(d.data.ptr + 18, _tysize[TYnptr]);   // size
1201     memcpy(d.data.ptr + 20, id, idlen);
1202     d.data.ptr[20 + idlen] = 0;
1203 
1204 }
1205     return cv_debtyp(d);
1206 }
1207 
1208 }
1209 
1210 }