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 }