1 /**
2  * Pretty print data structures
3  *
4  * Compiler implementation of the
5  * $(LINK2 https://www.dlang.org, D programming language).
6  *
7  * Copyright:   Copyright (C) 1985-1998 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/debug.c, backend/debugprint.d)
12  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/debug.c
13  */
14 
15 module dmd.backend.debugprint;
16 
17 version (SCPP)
18     version = COMPILE;
19 version (MARS)
20     version = COMPILE;
21 version (HTOD)
22     version = COMPILE;
23 
24 version (COMPILE)
25 {
26 
27 import core.stdc.stdio;
28 import core.stdc.stdlib;
29 import core.stdc.string;
30 
31 import dmd.backend.cdef;
32 import dmd.backend.cc;
33 import dmd.backend.el;
34 import dmd.backend.global;
35 import dmd.backend.code;
36 import dmd.backend.code_x86;
37 import dmd.backend.goh;
38 import dmd.backend.oper;
39 import dmd.backend.symtab;
40 import dmd.backend.ty;
41 import dmd.backend.type;
42 
43 import dmd.backend.dlist;
44 import dmd.backend.dvec;
45 
46 extern (C++):
47 
48 nothrow:
49 @safe:
50 
51 @trusted
52 void ferr(const(char)* p) { printf("%s", p); }
53 
54 /*******************************
55  * Write out storage class.
56  */
57 
58 @trusted
59 const(char)* class_str(SC c)
60 {
61     __gshared const char[10][SCMAX] sc =
62     [
63         "unde",
64         "auto",
65         "static",
66         "thread",
67         "extern",
68         "register",
69         "pseudo",
70         "global",
71         "comdat",
72         "parameter",
73         "regpar",
74         "fastpar",
75         "shadowreg",
76         "typedef",
77         "explicit",
78         "mutable",
79         "label",
80         "struct",
81         "enum",
82         "field",
83         "const",
84         "member",
85         "anon",
86         "inline",
87         "sinline",
88         "einline",
89         "overload",
90         "friend",
91         "virtual",
92         "locstat",
93         "template",
94         "functempl",
95         "ftexpspec",
96         "linkage",
97         "public",
98         "comdef",
99         "bprel",
100         "namespace",
101         "alias",
102         "funcalias",
103         "memalias",
104         "stack",
105         "adl",
106     ];
107     __gshared char[9 + 3] buffer;
108 
109     static assert(sc.length == SCMAX);
110     if (cast(uint) c < SCMAX)
111         snprintf(buffer.ptr,buffer.length,"SC%s",sc[c].ptr);
112     else
113         snprintf(buffer.ptr,buffer.length,"SC%u",cast(uint)c);
114     assert(strlen(buffer.ptr) < buffer.length);
115     return buffer.ptr;
116 }
117 
118 /***************************
119  * Convert OPER to string.
120  * Params:
121  *      oper = operator number
122  * Returns:
123  *      pointer to string
124  */
125 
126 const(char)* oper_str(uint oper) pure
127 {
128     assert(oper < OPMAX);
129     return &debtab[oper][0];
130 }
131 
132 /*******************************
133  * Convert tym_t to string.
134  * Params:
135  *      ty = type number
136  * Returns:
137  *      pointer to malloc'd string
138  */
139 @trusted
140 const(char)* tym_str(tym_t ty)
141 {
142     enum MAX = 100;
143     __gshared char[MAX + 1] buf;
144 
145     char* pstart = &buf[0];
146     char* p = pstart;
147     *p = 0;
148     if (ty & mTYnear)
149         strcat(p, "mTYnear|");
150     if (ty & mTYfar)
151         strcat(p, "mTYfar|");
152     if (ty & mTYcs)
153         strcat(p, "mTYcs|");
154     if (ty & mTYconst)
155         strcat(p, "mTYconst|");
156     if (ty & mTYvolatile)
157         strcat(p, "mTYvolatile|");
158     if (ty & mTYshared)
159         strcat(p, "mTYshared|");
160     if (ty & mTYxmmgpr)
161         strcat(p, "mTYxmmgpr|");
162     if (ty & mTYgprxmm)
163         strcat(p, "mTYgprxmm|");
164     const tyb = tybasic(ty);
165     if (tyb >= TYMAX)
166     {
167         printf("TY %x\n",cast(int)ty);
168         assert(0);
169     }
170     strcat(p, "TY");
171     strcat(p, tystring[tyb]);
172     assert(strlen(p) <= MAX);
173     return strdup(p);
174 }
175 
176 /*******************************
177  * Convert BC to string.
178  * Params:
179  *      bc = block exit code
180  * Returns:
181  *      pointer to string
182  */
183 @trusted
184 const(char)* bc_str(uint bc)
185 {
186     __gshared const char[9][BCMAX] bcs =
187         ["BCunde  ","BCgoto  ","BCtrue  ","BCret   ","BCretexp",
188          "BCexit  ","BCasm   ","BCswitch","BCifthen","BCjmptab",
189          "BCtry   ","BCcatch ","BCjump  ",
190          "BC_try  ","BC_filte","BC_final","BC_ret  ","BC_excep",
191          "BCjcatch","BC_lpad ",
192         ];
193 
194     return bcs[bc].ptr;
195 }
196 
197 /************************
198  * Write arglst
199  */
200 
201 @trusted
202 void WRarglst(list_t a)
203 { int n = 1;
204 
205   if (!a) printf("0 args\n");
206   while (a)
207   {     const(char)* c = cast(const(char)*)list_ptr(a);
208         printf("arg %d: '%s'\n", n, c ? c : "NULL");
209         a = a.next;
210         n++;
211   }
212 }
213 
214 /***************************
215  * Write out equation elem.
216  */
217 
218 @trusted
219 void WReqn(elem *e)
220 { __gshared int nest;
221 
222   if (!e)
223         return;
224   if (OTunary(e.Eoper))
225   {
226         ferr(oper_str(e.Eoper));
227         ferr(" ");
228         if (OTbinary(e.EV.E1.Eoper))
229         {       nest++;
230                 ferr("(");
231                 WReqn(e.EV.E1);
232                 ferr(")");
233                 nest--;
234         }
235         else
236                 WReqn(e.EV.E1);
237   }
238   else if (e.Eoper == OPcomma && !nest)
239   {     WReqn(e.EV.E1);
240         printf(";\n\t");
241         WReqn(e.EV.E2);
242   }
243   else if (OTbinary(e.Eoper))
244   {
245         if (OTbinary(e.EV.E1.Eoper))
246         {       nest++;
247                 ferr("(");
248                 WReqn(e.EV.E1);
249                 ferr(")");
250                 nest--;
251         }
252         else
253                 WReqn(e.EV.E1);
254         ferr(" ");
255         ferr(oper_str(e.Eoper));
256         ferr(" ");
257         if (e.Eoper == OPstreq)
258             printf("%d", cast(int)type_size(e.ET));
259         ferr(" ");
260         if (OTbinary(e.EV.E2.Eoper))
261         {       nest++;
262                 ferr("(");
263                 WReqn(e.EV.E2);
264                 ferr(")");
265                 nest--;
266         }
267         else
268                 WReqn(e.EV.E2);
269   }
270   else
271   {
272         switch (e.Eoper)
273         {   case OPconst:
274                 elem_print_const(e);
275                 break;
276             case OPrelconst:
277                 ferr("#");
278                 goto case OPvar;
279 
280             case OPvar:
281                 printf("%s",e.EV.Vsym.Sident.ptr);
282                 if (e.EV.Vsym.Ssymnum != SYMIDX.max)
283                     printf("(%d)", cast(int) e.EV.Vsym.Ssymnum);
284                 if (e.EV.Voffset != 0)
285                 {
286                     if (e.EV.Voffset.sizeof == 8)
287                         printf(".x%llx", cast(ulong)e.EV.Voffset);
288                     else
289                         printf(".%d",cast(int)e.EV.Voffset);
290                 }
291                 break;
292             case OPasm:
293             case OPstring:
294                 printf("\"%s\"",e.EV.Vstring);
295                 if (e.EV.Voffset)
296                     printf("+%lld",cast(long)e.EV.Voffset);
297                 break;
298             case OPmark:
299             case OPgot:
300             case OPframeptr:
301             case OPhalt:
302             case OPdctor:
303             case OPddtor:
304                 ferr(oper_str(e.Eoper));
305                 ferr(" ");
306                 break;
307             case OPstrthis:
308                 break;
309             default:
310                 ferr(oper_str(e.Eoper));
311                 assert(0);
312         }
313   }
314 }
315 
316 @trusted
317 void WRblocklist(list_t bl)
318 {
319     foreach (bl2; ListRange(bl))
320     {
321         block *b = list_block(bl2);
322 
323         if (b && b.Bweight)
324             printf("B%d (%p) ",b.Bdfoidx,b);
325         else
326             printf("%p ",b);
327     }
328     ferr("\n");
329 }
330 
331 @trusted
332 void WRdefnod()
333 { int i;
334 
335   for (i = 0; i < go.defnod.length; i++)
336   {     printf("defnod[%d] in B%d = (", go.defnod[i].DNblock.Bdfoidx, i);
337         WReqn(go.defnod[i].DNelem);
338         printf(");\n");
339   }
340 }
341 
342 @trusted
343 void WRFL(FL fl)
344 {
345     __gshared const(char)[7][FLMAX] fls =
346     [    "unde  ","const ","oper  ","func  ","data  ",
347          "reg   ",
348          "pseudo",
349          "auto  ","fast  ","para  ","extrn ",
350          "code  ","block ","udata ","cs    ","swit  ",
351          "fltrg ","offst ","datsg ",
352          "ctor  ","dtor  ","regsav","asm   ",
353          "ndp   ",
354          "farda ","csdat ",
355          "local ","tlsdat",
356          "bprel ","frameh","blocko","alloca",
357          "stack ","dsym  ",
358          "got   ","gotoff",
359          "funcar",
360     ];
361 
362     if (cast(uint)fl >= FLMAX)
363         printf("FL%d",fl);
364     else
365       printf("FL%s",fls[fl].ptr);
366 }
367 
368 /***********************
369  * Write out block.
370  */
371 
372 @trusted
373 void WRblock(block *b)
374 {
375     if (OPTIMIZER)
376     {
377         if (b && b.Bweight)
378                 printf("B%d: (%p), weight=%d",b.Bdfoidx,b,b.Bweight);
379         else
380                 printf("block %p",b);
381         if (!b)
382         {       ferr("\n");
383                 return;
384         }
385         printf(" flags=x%x weight=%d",b.Bflags,b.Bweight);
386         //printf("\tfile %p, line %d",b.Bfilptr,b.Blinnum);
387         printf(" %s Btry=%p Bindex=%d",bc_str(b.BC),b.Btry,b.Bindex);
388         if (b.BC == BCtry)
389             printf(" catchvar = %p",b.catchvar);
390         printf("\n");
391         printf("\tBpred: "); WRblocklist(b.Bpred);
392         printf("\tBsucc: "); WRblocklist(b.Bsucc);
393         if (b.Belem)
394         {       if (debugf)                     /* if full output       */
395                         elem_print(b.Belem);
396                 else
397                 {       ferr("\t");
398                         WReqn(b.Belem);
399                         printf(";\n");
400                 }
401         }
402         version (MARS)
403         {
404         if (b.Bcode)
405             b.Bcode.print();
406         }
407         version (SCPP)
408         {
409         if (b.Bcode)
410             b.Bcode.print();
411         }
412         ferr("\n");
413     }
414     else
415     {
416         targ_llong *pu;
417         int ncases;
418 
419         assert(b);
420         printf("%2d: %s", b.Bnumber, bc_str(b.BC));
421         if (b.Btry)
422             printf(" Btry=B%d",b.Btry ? b.Btry.Bnumber : 0);
423         if (b.Bindex)
424             printf(" Bindex=%d",b.Bindex);
425         if (b.BC == BC_finally)
426             printf(" b_ret=B%d", b.b_ret ? b.b_ret.Bnumber : 0);
427 version (MARS)
428 {
429         if (b.Bsrcpos.Sfilename)
430             printf(" %s(%u)", b.Bsrcpos.Sfilename, b.Bsrcpos.Slinnum);
431 }
432         printf("\n");
433         if (b.Belem)
434         {
435             if (debugf)
436                 elem_print(b.Belem);
437             else
438             {
439                 ferr("\t");
440                 WReqn(b.Belem);
441                 printf(";\n");
442             }
443         }
444         if (b.Bpred)
445         {
446             printf("\tBpred:");
447             foreach (bl; ListRange(b.Bpred))
448                 printf(" B%d",list_block(bl).Bnumber);
449             printf("\n");
450         }
451         list_t bl = b.Bsucc;
452         switch (b.BC)
453         {
454             case BCswitch:
455                 pu = b.Bswitch;
456                 assert(pu);
457                 ncases = cast(int)*pu;
458                 printf("\tncases = %d\n",ncases);
459                 printf("\tdefault: B%d\n",list_block(bl) ? list_block(bl).Bnumber : 0);
460                 while (ncases--)
461                 {   bl = list_next(bl);
462                     printf("\tcase %lld: B%d\n", cast(long)*++pu,list_block(bl).Bnumber);
463                 }
464                 break;
465             case BCiftrue:
466             case BCgoto:
467             case BCasm:
468             case BCtry:
469             case BCcatch:
470             case BCjcatch:
471             case BC_try:
472             case BC_filter:
473             case BC_finally:
474             case BC_lpad:
475             case BC_ret:
476             case BC_except:
477 
478                 if (bl)
479                 {
480                     printf("\tBsucc:");
481                     for ( ; bl; bl = list_next(bl))
482                         printf(" B%d",list_block(bl).Bnumber);
483                     printf("\n");
484                 }
485                 break;
486             case BCret:
487             case BCretexp:
488             case BCexit:
489                 break;
490             default:
491                 printf("bc = %d\n", b.BC);
492                 assert(0);
493         }
494     }
495 }
496 
497 /*****************************
498  * Number the blocks starting at 1.
499  * So much more convenient than pointer values.
500  */
501 @safe
502 void numberBlocks(block *startblock)
503 {
504     uint number = 0;
505     for (block *b = startblock; b; b = b.Bnext)
506         b.Bnumber = ++number;
507 }
508 
509 /**************************************
510  * Print out the intermediate code for a function.
511  * Params:
512  *      msg = label for the print
513  *      sfunc = function to print
514  *      startblock = intermediate code
515  */
516 @trusted
517 void WRfunc(const char* msg, Symbol* sfunc, block* startblock)
518 {
519     printf("............%s...%s().............\n", msg, sfunc.Sident.ptr);
520     numberBlocks(startblock);
521     for (block *b = startblock; b; b = b.Bnext)
522         WRblock(b);
523 }
524 
525 }