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