1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)eval.c	5.3 (Berkeley) 6/21/85";
   9: #endif not lint
  10: 
  11: static char rcsid[] = "$Header: eval.c,v 1.5 84/12/26 10:39:08 linton Exp $";
  12: 
  13: /*
  14:  * Tree evaluation.
  15:  */
  16: 
  17: #include "defs.h"
  18: #include "tree.h"
  19: #include "operators.h"
  20: #include "debug.h"
  21: #include "eval.h"
  22: #include "events.h"
  23: #include "symbols.h"
  24: #include "scanner.h"
  25: #include "source.h"
  26: #include "object.h"
  27: #include "mappings.h"
  28: #include "process.h"
  29: #include "runtime.h"
  30: #include "machine.h"
  31: #include <signal.h>
  32: 
  33: #ifndef public
  34: 
  35: #include "machine.h"
  36: 
  37: #define STACKSIZE 20000
  38: 
  39: typedef Char Stack;
  40: 
  41: #define push(type, value) { \
  42:     ((type *) (sp += sizeof(type)))[-1] = (value); \
  43: }
  44: 
  45: #define pop(type) ( \
  46:     (*((type *) (sp -= sizeof(type)))) \
  47: )
  48: 
  49: #define popn(n, dest) { \
  50:     sp -= n; \
  51:     bcopy(sp, dest, n); \
  52: }
  53: 
  54: #define alignstack() { \
  55:     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
  56: }
  57: 
  58: #endif
  59: 
  60: public Stack stack[STACKSIZE];
  61: public Stack *sp = &stack[0];
  62: public Boolean useInstLoc = false;
  63: 
  64: #define chksp() \
  65: { \
  66:     if (sp < &stack[0]) { \
  67:     panic("stack underflow"); \
  68:     } \
  69: }
  70: 
  71: #define poparg(n, r, fr) { \
  72:     eval(p->value.arg[n]); \
  73:     if (isreal(p->op)) { \
  74:     if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
  75:         fr = pop(float); \
  76:     } else { \
  77:         fr = pop(double); \
  78:     } \
  79:     } else if (isint(p->op)) { \
  80:     r = popsmall(p->value.arg[n]->nodetype); \
  81:     } \
  82: }
  83: 
  84: #define Boolrep char    /* underlying representation type for booleans */
  85: 
  86: /*
  87:  * Command-level evaluation.
  88:  */
  89: 
  90: public Node topnode;
  91: 
  92: public topeval (p)
  93: Node p;
  94: {
  95:     if (traceeval) {
  96:     fprintf(stderr, "topeval(");
  97:     prtree(stderr, p);
  98:     fprintf(stderr, ")\n");
  99:     fflush(stderr);
 100:     }
 101:     topnode = p;
 102:     eval(p);
 103: }
 104: 
 105: /*
 106:  * Evaluate a parse tree leaving the value on the top of the stack.
 107:  */
 108: 
 109: public eval(p)
 110: register Node p;
 111: {
 112:     long r0, r1;
 113:     double fr0, fr1;
 114:     Address addr;
 115:     long i, n;
 116:     int len;
 117:     Symbol s;
 118:     Node n1, n2;
 119:     boolean b;
 120:     File file;
 121:     String str;
 122: 
 123:     checkref(p);
 124:     if (traceeval) {
 125:     fprintf(stderr, "begin eval %s\n", opname(p->op));
 126:     }
 127:     switch (degree(p->op)) {
 128:     case BINARY:
 129:         poparg(1, r1, fr1);
 130:         poparg(0, r0, fr0);
 131:         break;
 132: 
 133:     case UNARY:
 134:         poparg(0, r0, fr0);
 135:         break;
 136: 
 137:     default:
 138:         /* do nothing */;
 139:     }
 140:     switch (p->op) {
 141:     case O_SYM:
 142:         s = p->value.sym;
 143:         if (s == retaddrsym) {
 144:         push(long, return_addr());
 145:         } else if (isvariable(s)) {
 146:         if (s != program and not isactive(container(s))) {
 147:             error("\"%s\" is not active", symname(s));
 148:         }
 149:         if (isvarparam(s) and not isopenarray(s)) {
 150:             rpush(address(s, nil), sizeof(Address));
 151:         } else {
 152:             push(Address, address(s, nil));
 153:         }
 154:         } else if (isblock(s)) {
 155:         push(Symbol, s);
 156:         } else if (isconst(s)) {
 157:         eval(constval(s));
 158:         } else {
 159:         error("can't evaluate a %s", classname(s));
 160:         }
 161:         break;
 162: 
 163:     case O_LCON:
 164:     case O_CCON:
 165:         r0 = p->value.lcon;
 166:         pushsmall(p->nodetype, r0);
 167:         break;
 168: 
 169:     case O_FCON:
 170:         push(double, p->value.fcon);
 171:         break;
 172: 
 173:     case O_SCON:
 174:         len = size(p->nodetype);
 175:         mov(p->value.scon, sp, len);
 176:         sp += len;
 177:         break;
 178: 
 179:     case O_INDEX:
 180:         s = p->value.arg[0]->nodetype;
 181:         p->value.arg[0]->nodetype = t_addr;
 182:         eval(p->value.arg[0]);
 183:         p->value.arg[0]->nodetype = s;
 184:         n = pop(Address);
 185:         eval(p->value.arg[1]);
 186:         evalindex(s, n, popsmall(p->value.arg[1]->nodetype));
 187:         break;
 188: 
 189:     case O_DOT:
 190:         s = p->value.arg[1]->value.sym;
 191:         eval(p->value.arg[0]);
 192:         n = pop(long);
 193:         push(long, n + (s->symvalue.field.offset div 8));
 194:         break;
 195: 
 196:     /*
 197: 	 * Get the value of the expression addressed by the top of the stack.
 198: 	 * Push the result back on the stack.
 199: 	 */
 200: 
 201:     case O_INDIR:
 202:     case O_RVAL:
 203:         addr = pop(long);
 204:         if (addr == 0) {
 205:         error("reference through nil pointer");
 206:         }
 207:         len = size(p->nodetype);
 208:         rpush(addr, len);
 209:         break;
 210: 
 211:     /*
 212: 	 * Move the stack pointer so that the top of the stack has
 213: 	 * something corresponding to the size of the current node type.
 214: 	 * If this new type is bigger than the subtree (len > 0),
 215: 	 * then the stack is padded with nulls.  If it's smaller,
 216: 	 * the stack is just dropped by the appropriate amount.
 217: 	 */
 218:     case O_TYPERENAME:
 219:         len = size(p->nodetype) - size(p->value.arg[0]->nodetype);
 220:         if (len > 0) {
 221:         for (n = 0; n < len; n++) {
 222:             *sp++ = '\0';
 223:         }
 224:         } else if (len < 0) {
 225:         sp += len;
 226:         }
 227:         break;
 228: 
 229:     case O_COMMA:
 230:         eval(p->value.arg[0]);
 231:         if (p->value.arg[1] != nil) {
 232:         eval(p->value.arg[1]);
 233:         }
 234:         break;
 235: 
 236:     case O_ITOF:
 237:         push(double, (double) r0);
 238:         break;
 239: 
 240:     case O_ADD:
 241:         push(long, r0+r1);
 242:         break;
 243: 
 244:     case O_ADDF:
 245:         push(double, fr0+fr1);
 246:         break;
 247: 
 248:     case O_SUB:
 249:         push(long, r0-r1);
 250:         break;
 251: 
 252:     case O_SUBF:
 253:         push(double, fr0-fr1);
 254:         break;
 255: 
 256:     case O_NEG:
 257:         push(long, -r0);
 258:         break;
 259: 
 260:     case O_NEGF:
 261:         push(double, -fr0);
 262:         break;
 263: 
 264:     case O_MUL:
 265:         push(long, r0*r1);
 266:         break;
 267: 
 268:     case O_MULF:
 269:         push(double, fr0*fr1);
 270:         break;
 271: 
 272:     case O_DIVF:
 273:         if (fr1 == 0) {
 274:         error("error: division by 0");
 275:         }
 276:         push(double, fr0 / fr1);
 277:         break;
 278: 
 279:     case O_DIV:
 280:         if (r1 == 0) {
 281:         error("error: div by 0");
 282:         }
 283:         push(long, r0 div r1);
 284:         break;
 285: 
 286:     case O_MOD:
 287:         if (r1 == 0) {
 288:         error("error: mod by 0");
 289:         }
 290:         push(long, r0 mod r1);
 291:         break;
 292: 
 293:     case O_LT:
 294:         push(Boolrep, r0 < r1);
 295:         break;
 296: 
 297:     case O_LTF:
 298:         push(Boolrep, fr0 < fr1);
 299:         break;
 300: 
 301:     case O_LE:
 302:         push(Boolrep, r0 <= r1);
 303:         break;
 304: 
 305:     case O_LEF:
 306:         push(Boolrep, fr0 <= fr1);
 307:         break;
 308: 
 309:     case O_GT:
 310:         push(Boolrep, r0 > r1);
 311:         break;
 312: 
 313:     case O_GTF:
 314:         push(Boolrep, fr0 > fr1);
 315:         break;
 316: 
 317:     case O_EQ:
 318:         push(Boolrep, r0 == r1);
 319:         break;
 320: 
 321:     case O_EQF:
 322:         push(Boolrep, fr0 == fr1);
 323:         break;
 324: 
 325:     case O_NE:
 326:         push(Boolrep, r0 != r1);
 327:         break;
 328: 
 329:     case O_NEF:
 330:         push(Boolrep, fr0 != fr1);
 331:         break;
 332: 
 333:     case O_AND:
 334:         push(Boolrep, r0 and r1);
 335:         break;
 336: 
 337:     case O_OR:
 338:         push(Boolrep, r0 or r1);
 339:         break;
 340: 
 341:     case O_ASSIGN:
 342:         assign(p->value.arg[0], p->value.arg[1]);
 343:         break;
 344: 
 345:     case O_CHFILE:
 346:         if (p->value.scon == nil) {
 347:         printf("%s\n", cursource);
 348:         } else {
 349:         file = opensource(p->value.scon);
 350:         if (file == nil) {
 351:             error("can't read \"%s\"", p->value.scon);
 352:         } else {
 353:             fclose(file);
 354:             setsource(p->value.scon);
 355:         }
 356:         }
 357:         break;
 358: 
 359:     case O_CONT:
 360:         cont(p->value.lcon);
 361:         printnews();
 362:         break;
 363: 
 364:     case O_LIST:
 365:         list(p);
 366:         break;
 367: 
 368:     case O_FUNC:
 369:         func(p->value.arg[0]);
 370:         break;
 371: 
 372:     case O_EXAMINE:
 373:         eval(p->value.examine.beginaddr);
 374:         r0 = pop(long);
 375:         if (p->value.examine.endaddr == nil) {
 376:         n = p->value.examine.count;
 377:         if (n == 0) {
 378:             printvalue(r0, p->value.examine.mode);
 379:         } else if (streq(p->value.examine.mode, "i")) {
 380:             printninst(n, (Address) r0);
 381:         } else {
 382:             printndata(n, (Address) r0, p->value.examine.mode);
 383:         }
 384:         } else {
 385:         eval(p->value.examine.endaddr);
 386:         r1 = pop(long);
 387:         if (streq(p->value.examine.mode, "i")) {
 388:             printinst((Address)r0, (Address)r1);
 389:         } else {
 390:             printdata((Address)r0, (Address)r1, p->value.examine.mode);
 391:         }
 392:         }
 393:         break;
 394: 
 395:     case O_PRINT:
 396:         for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
 397:         eval(n1->value.arg[0]);
 398:         printval(n1->value.arg[0]->nodetype);
 399:         putchar(' ');
 400:         }
 401:         putchar('\n');
 402:         break;
 403: 
 404:     case O_PSYM:
 405:         if (p->value.arg[0]->op == O_SYM) {
 406:         psym(p->value.arg[0]->value.sym);
 407:         } else {
 408:         psym(p->value.arg[0]->nodetype);
 409:         }
 410:         break;
 411: 
 412:     case O_QLINE:
 413:         eval(p->value.arg[1]);
 414:         break;
 415: 
 416:     case O_STEP:
 417:         b = inst_tracing;
 418:         inst_tracing = (Boolean) (not p->value.step.source);
 419:         if (p->value.step.skipcalls) {
 420:         next();
 421:         } else {
 422:         stepc();
 423:         }
 424:         inst_tracing = b;
 425:         useInstLoc = (Boolean) (not p->value.step.source);
 426:         printnews();
 427:         break;
 428: 
 429:     case O_WHATIS:
 430:         if (p->value.arg[0]->op == O_SYM) {
 431:         printdecl(p->value.arg[0]->value.sym);
 432:         } else {
 433:         printdecl(p->value.arg[0]->nodetype);
 434:         }
 435:         break;
 436: 
 437:     case O_WHERE:
 438:         wherecmd();
 439:         break;
 440: 
 441:     case O_WHEREIS:
 442:         if (p->value.arg[0]->op == O_SYM) {
 443:         printwhereis(stdout, p->value.arg[0]->value.sym);
 444:         } else {
 445:         printwhereis(stdout, p->value.arg[0]->nodetype);
 446:         }
 447:         break;
 448: 
 449:     case O_WHICH:
 450:         if (p->value.arg[0]->op == O_SYM) {
 451:         printwhich(stdout, p->value.arg[0]->value.sym);
 452:         } else {
 453:         printwhich(stdout, p->value.arg[0]->nodetype);
 454:         }
 455:         putchar('\n');
 456:         break;
 457: 
 458:     case O_ALIAS:
 459:         n1 = p->value.arg[0];
 460:         n2 = p->value.arg[1];
 461:         if (n2 == nil) {
 462:         if (n1 == nil) {
 463:             alias(nil, nil, nil);
 464:         } else {
 465:             alias(n1->value.name, nil, nil);
 466:         }
 467:         } else if (n2->op == O_NAME) {
 468:         str = ident(n2->value.name);
 469:         alias(n1->value.name, nil, strdup(str));
 470:         } else {
 471:         if (n1->op == O_COMMA) {
 472:             alias(
 473:             n1->value.arg[0]->value.name,
 474:             (List) n1->value.arg[1],
 475:             n2->value.scon
 476:             );
 477:         } else {
 478:             alias(n1->value.name, nil, n2->value.scon);
 479:         }
 480:         }
 481:         break;
 482: 
 483:     case O_UNALIAS:
 484:         unalias(p->value.arg[0]->value.name);
 485:         break;
 486: 
 487:     case O_CALLPROC:
 488:         callproc(p, false);
 489:         break;
 490: 
 491:     case O_CALL:
 492:         callproc(p, true);
 493:         break;
 494: 
 495:     case O_CATCH:
 496:         if (p->value.lcon == 0) {
 497:         printsigscaught(process);
 498:         } else {
 499:         psigtrace(process, p->value.lcon, true);
 500:         }
 501:         break;
 502: 
 503:     case O_EDIT:
 504:         edit(p->value.scon);
 505:         break;
 506: 
 507:         case O_DEBUG:
 508:             debug(p);
 509:         break;
 510: 
 511:     case O_DOWN:
 512:         checkref(p->value.arg[0]);
 513:         assert(p->value.arg[0]->op == O_LCON);
 514:         down(p->value.arg[0]->value.lcon);
 515:         break;
 516: 
 517:     case O_DUMP:
 518:         if (p->value.arg[0] == nil) {
 519:         dumpall();
 520:         } else {
 521:         s = p->value.arg[0]->value.sym;
 522:         if (s == curfunc) {
 523:             dump(nil);
 524:         } else {
 525:             dump(s);
 526:         }
 527:         }
 528:         break;
 529: 
 530:     case O_GRIPE:
 531:         gripe();
 532:         break;
 533: 
 534:     case O_HELP:
 535:         help();
 536:         break;
 537: 
 538:     case O_IGNORE:
 539:         if (p->value.lcon == 0) {
 540:         printsigsignored(process);
 541:         } else {
 542:         psigtrace(process, p->value.lcon, false);
 543:         }
 544:         break;
 545: 
 546:     case O_RETURN:
 547:         if (p->value.arg[0] == nil) {
 548:         rtnfunc(nil);
 549:         } else {
 550:         assert(p->value.arg[0]->op == O_SYM);
 551:         rtnfunc(p->value.arg[0]->value.sym);
 552:         }
 553:         break;
 554: 
 555:     case O_RUN:
 556:         run();
 557:         break;
 558: 
 559:     case O_SET:
 560:         set(p->value.arg[0], p->value.arg[1]);
 561:         break;
 562: 
 563:     case O_SEARCH:
 564:         search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon);
 565:         break;
 566: 
 567:     case O_SOURCE:
 568:         setinput(p->value.scon);
 569:         break;
 570: 
 571:     case O_STATUS:
 572:         status();
 573:         break;
 574: 
 575:     case O_TRACE:
 576:     case O_TRACEI:
 577:         trace(p);
 578:         break;
 579: 
 580:     case O_STOP:
 581:     case O_STOPI:
 582:         stop(p);
 583:         break;
 584: 
 585:     case O_UNSET:
 586:         undefvar(p->value.arg[0]->value.name);
 587:         break;
 588: 
 589:     case O_UP:
 590:         checkref(p->value.arg[0]);
 591:         assert(p->value.arg[0]->op == O_LCON);
 592:         up(p->value.arg[0]->value.lcon);
 593:         break;
 594: 
 595:     case O_ADDEVENT:
 596:         addevent(p->value.event.cond, p->value.event.actions);
 597:         break;
 598: 
 599:     case O_DELETE:
 600:         n1 = p->value.arg[0];
 601:         while (n1->op == O_COMMA) {
 602:         n2 = n1->value.arg[0];
 603:         assert(n2->op == O_LCON);
 604:         if (not delevent((unsigned int) n2->value.lcon)) {
 605:             error("unknown event %ld", n2->value.lcon);
 606:         }
 607:         n1 = n1->value.arg[1];
 608:         }
 609:         assert(n1->op == O_LCON);
 610:         if (not delevent((unsigned int) n1->value.lcon)) {
 611:         error("unknown event %ld", n1->value.lcon);
 612:         }
 613:         break;
 614: 
 615:     case O_ENDX:
 616:         endprogram();
 617:         break;
 618: 
 619:     case O_IF:
 620:         if (cond(p->value.event.cond)) {
 621:         evalcmdlist(p->value.event.actions);
 622:         }
 623:         break;
 624: 
 625:     case O_ONCE:
 626:         event_once(p->value.event.cond, p->value.event.actions);
 627:         break;
 628: 
 629:     case O_PRINTCALL:
 630:         printcall(p->value.sym, whatblock(return_addr()));
 631:         break;
 632: 
 633:     case O_PRINTIFCHANGED:
 634:         printifchanged(p->value.arg[0]);
 635:         break;
 636: 
 637:     case O_PRINTRTN:
 638:         printrtn(p->value.sym);
 639:         break;
 640: 
 641:     case O_PRINTSRCPOS:
 642:         getsrcpos();
 643:         if (p->value.arg[0] == nil) {
 644:         printsrcpos();
 645:         putchar('\n');
 646:         printlines(curline, curline);
 647:         } else if (p->value.arg[0]->op == O_QLINE) {
 648:         if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
 649:             printf("tracei: ");
 650:             printinst(pc, pc);
 651:         } else {
 652:             if (canReadSource()) {
 653:             printf("trace:  ");
 654:             printlines(curline, curline);
 655:             }
 656:         }
 657:         } else {
 658:         printsrcpos();
 659:         printf(": ");
 660:         eval(p->value.arg[0]);
 661:         prtree(stdout, p->value.arg[0]);
 662:         printf(" = ");
 663:         printval(p->value.arg[0]->nodetype);
 664:         putchar('\n');
 665:         }
 666:         break;
 667: 
 668:     case O_PROCRTN:
 669:         procreturn(p->value.sym);
 670:         break;
 671: 
 672:     case O_STOPIFCHANGED:
 673:         stopifchanged(p->value.arg[0]);
 674:         break;
 675: 
 676:     case O_STOPX:
 677:         isstopped = true;
 678:         break;
 679: 
 680:     case O_TRACEON:
 681:         traceon(p->value.trace.inst, p->value.trace.event,
 682:         p->value.trace.actions);
 683:         break;
 684: 
 685:     case O_TRACEOFF:
 686:         traceoff(p->value.lcon);
 687:         break;
 688: 
 689:     default:
 690:         panic("eval: bad op %d", p->op);
 691:     }
 692:     if (traceeval) {
 693:     fprintf(stderr, "end eval %s\n", opname(p->op));
 694:     }
 695: }
 696: 
 697: /*
 698:  * Evaluate a list of commands.
 699:  */
 700: 
 701: public evalcmdlist(cl)
 702: Cmdlist cl;
 703: {
 704:     Command c;
 705: 
 706:     foreach (Command, c, cl)
 707:     evalcmd(c);
 708:     endfor
 709: }
 710: 
 711: /*
 712:  * Push "len" bytes onto the expression stack from address "addr"
 713:  * in the process.  If there isn't room on the stack, print an error message.
 714:  */
 715: 
 716: public rpush(addr, len)
 717: Address addr;
 718: int len;
 719: {
 720:     if (not canpush(len)) {
 721:     error("expression too large to evaluate");
 722:     } else {
 723:     chksp();
 724:     dread(sp, addr, len);
 725:     sp += len;
 726:     }
 727: }
 728: 
 729: /*
 730:  * Check if the stack has n bytes available.
 731:  */
 732: 
 733: public Boolean canpush(n)
 734: Integer n;
 735: {
 736:     return (Boolean) (sp + n < &stack[STACKSIZE]);
 737: }
 738: 
 739: /*
 740:  * Push a small scalar of the given type onto the stack.
 741:  */
 742: 
 743: public pushsmall(t, v)
 744: Symbol t;
 745: long v;
 746: {
 747:     register Integer s;
 748: 
 749:     s = size(t);
 750:     switch (s) {
 751:     case sizeof(char):
 752:         push(char, v);
 753:         break;
 754: 
 755:     case sizeof(short):
 756:         push(short, v);
 757:         break;
 758: 
 759:     case sizeof(long):
 760:         push(long, v);
 761:         break;
 762: 
 763:     default:
 764:         panic("bad size %d in popsmall", s);
 765:     }
 766: }
 767: 
 768: /*
 769:  * Pop an item of the given type which is assumed to be no larger
 770:  * than a long and return it expanded into a long.
 771:  */
 772: 
 773: public long popsmall(t)
 774: Symbol t;
 775: {
 776:     register integer n;
 777:     long r;
 778: 
 779:     n = size(t);
 780:     if (n == sizeof(char)) {
 781:     if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
 782:         r = (long) pop(unsigned char);
 783:     } else {
 784:         r = (long) pop(char);
 785:     }
 786:     } else if (n == sizeof(short)) {
 787:     if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
 788:         r = (long) pop(unsigned short);
 789:     } else {
 790:         r = (long) pop(short);
 791:     }
 792:     } else if (n == sizeof(long)) {
 793:     r = pop(long);
 794:     } else {
 795:     error("[internal error: size %d in popsmall]", n);
 796:     }
 797:     return r;
 798: }
 799: 
 800: /*
 801:  * Evaluate a conditional expression.
 802:  */
 803: 
 804: public Boolean cond(p)
 805: Node p;
 806: {
 807:     register Boolean b;
 808: 
 809:     if (p == nil) {
 810:     b = true;
 811:     } else {
 812:     eval(p);
 813:     b = (Boolean) pop(Boolrep);
 814:     }
 815:     return b;
 816: }
 817: 
 818: /*
 819:  * Return the address corresponding to a given tree.
 820:  */
 821: 
 822: public Address lval(p)
 823: Node p;
 824: {
 825:     if (p->op == O_RVAL) {
 826:     eval(p->value.arg[0]);
 827:     } else {
 828:     eval(p);
 829:     }
 830:     return (Address) (pop(long));
 831: }
 832: 
 833: /*
 834:  * Process a trace command, translating into the appropriate events
 835:  * and associated actions.
 836:  */
 837: 
 838: public trace(p)
 839: Node p;
 840: {
 841:     Node exp, place, cond;
 842:     Node left;
 843: 
 844:     exp = p->value.arg[0];
 845:     place = p->value.arg[1];
 846:     cond = p->value.arg[2];
 847:     if (exp == nil) {
 848:     traceall(p->op, place, cond);
 849:     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
 850:     traceinst(p->op, exp, cond);
 851:     } else if (place != nil and place->op == O_QLINE) {
 852:     traceat(p->op, exp, place, cond);
 853:     } else {
 854:     left = exp;
 855:     if (left->op == O_RVAL or left->op == O_CALL) {
 856:         left = left->value.arg[0];
 857:     }
 858:     if (left->op == O_SYM and isblock(left->value.sym)) {
 859:         traceproc(p->op, left->value.sym, place, cond);
 860:     } else {
 861:         tracedata(p->op, exp, place, cond);
 862:     }
 863:     }
 864: }
 865: 
 866: /*
 867:  * Set a breakpoint that will turn on tracing.
 868:  */
 869: 
 870: private traceall(op, place, cond)
 871: Operator op;
 872: Node place;
 873: Node cond;
 874: {
 875:     Symbol s;
 876:     Node event;
 877:     Command action;
 878: 
 879:     if (place == nil) {
 880:     s = program;
 881:     } else {
 882:     s = place->value.sym;
 883:     }
 884:     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
 885:     action = build(O_PRINTSRCPOS,
 886:     build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
 887:     if (cond != nil) {
 888:     action = build(O_IF, cond, buildcmdlist(action));
 889:     }
 890:     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
 891:     action->value.trace.event = addevent(event, buildcmdlist(action));
 892:     if (isstdin()) {
 893:     printevent(action->value.trace.event);
 894:     }
 895: }
 896: 
 897: /*
 898:  * Set up the appropriate breakpoint for tracing an instruction.
 899:  */
 900: 
 901: private traceinst(op, exp, cond)
 902: Operator op;
 903: Node exp;
 904: Node cond;
 905: {
 906:     Node event, wh;
 907:     Command action;
 908:     Event e;
 909: 
 910:     if (exp->op == O_LCON) {
 911:     wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp);
 912:     } else {
 913:     wh = exp;
 914:     }
 915:     if (op == O_TRACEI) {
 916:     event = build(O_EQ, build(O_SYM, pcsym), wh);
 917:     } else {
 918:     event = build(O_EQ, build(O_SYM, linesym), wh);
 919:     }
 920:     action = build(O_PRINTSRCPOS, wh);
 921:     if (cond) {
 922:     action = build(O_IF, cond, buildcmdlist(action));
 923:     }
 924:     e = addevent(event, buildcmdlist(action));
 925:     if (isstdin()) {
 926:     printevent(e);
 927:     }
 928: }
 929: 
 930: /*
 931:  * Set a breakpoint to print an expression at a given line or address.
 932:  */
 933: 
 934: private traceat(op, exp, place, cond)
 935: Operator op;
 936: Node exp;
 937: Node place;
 938: Node cond;
 939: {
 940:     Node event;
 941:     Command action;
 942:     Event e;
 943: 
 944:     if (op == O_TRACEI) {
 945:     event = build(O_EQ, build(O_SYM, pcsym), place);
 946:     } else {
 947:     event = build(O_EQ, build(O_SYM, linesym), place);
 948:     }
 949:     action = build(O_PRINTSRCPOS, exp);
 950:     if (cond != nil) {
 951:     action = build(O_IF, cond, buildcmdlist(action));
 952:     }
 953:     e = addevent(event, buildcmdlist(action));
 954:     if (isstdin()) {
 955:     printevent(e);
 956:     }
 957: }
 958: 
 959: /*
 960:  * Construct event for tracing a procedure.
 961:  *
 962:  * What we want here is
 963:  *
 964:  * 	when $proc = p do
 965:  *	    if <condition> then
 966:  *	        printcall;
 967:  *	        once $pc = $retaddr do
 968:  *	            printrtn;
 969:  *	        end;
 970:  *	    end if;
 971:  *	end;
 972:  *
 973:  * Note that "once" is like "when" except that the event
 974:  * deletes itself as part of its associated action.
 975:  */
 976: 
 977: private traceproc(op, p, place, cond)
 978: Operator op;
 979: Symbol p;
 980: Node place;
 981: Node cond;
 982: {
 983:     Node event;
 984:     Command action;
 985:     Cmdlist actionlist;
 986:     Event e;
 987: 
 988:     action = build(O_PRINTCALL, p);
 989:     actionlist = list_alloc();
 990:     cmdlist_append(action, actionlist);
 991:     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
 992:     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
 993:     cmdlist_append(action, actionlist);
 994:     if (cond != nil) {
 995:     actionlist = buildcmdlist(build(O_IF, cond, actionlist));
 996:     }
 997:     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
 998:     e = addevent(event, actionlist);
 999:     if (isstdin()) {
1000:     printevent(e);
1001:     }
1002: }
1003: 
1004: /*
1005:  * Set up breakpoint for tracing data.
1006:  */
1007: 
1008: private tracedata(op, exp, place, cond)
1009: Operator op;
1010: Node exp;
1011: Node place;
1012: Node cond;
1013: {
1014:     Symbol p;
1015:     Node event;
1016:     Command action;
1017: 
1018:     p = (place == nil) ? tcontainer(exp) : place->value.sym;
1019:     if (p == nil) {
1020:     p = program;
1021:     }
1022:     action = build(O_PRINTIFCHANGED, exp);
1023:     if (cond != nil) {
1024:     action = build(O_IF, cond, buildcmdlist(action));
1025:     }
1026:     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
1027:     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
1028:     action->value.trace.event = addevent(event, buildcmdlist(action));
1029:     if (isstdin()) {
1030:     printevent(action->value.trace.event);
1031:     }
1032: }
1033: 
1034: /*
1035:  * Setting and unsetting of stops.
1036:  */
1037: 
1038: public stop(p)
1039: Node p;
1040: {
1041:     Node exp, place, cond, t;
1042:     Symbol s;
1043:     Command action;
1044:     Event e;
1045: 
1046:     exp = p->value.arg[0];
1047:     place = p->value.arg[1];
1048:     cond = p->value.arg[2];
1049:     if (exp != nil) {
1050:     stopvar(p->op, exp, place, cond);
1051:     } else {
1052:     action = build(O_STOPX);
1053:     if (cond != nil) {
1054:         action = build(O_IF, cond, buildcmdlist(action));
1055:     }
1056:     if (place == nil or place->op == O_SYM) {
1057:         if (place == nil) {
1058:         s = program;
1059:         } else {
1060:         s = place->value.sym;
1061:         }
1062:         t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
1063:         if (cond != nil) {
1064:         action = build(O_TRACEON, (p->op == O_STOPI),
1065:             buildcmdlist(action));
1066:         e = addevent(t, buildcmdlist(action));
1067:         action->value.trace.event = e;
1068:         } else {
1069:         e = addevent(t, buildcmdlist(action));
1070:         }
1071:         if (isstdin()) {
1072:         printevent(e);
1073:         }
1074:     } else {
1075:         stopinst(p->op, place, cond, action);
1076:     }
1077:     }
1078: }
1079: 
1080: private stopinst(op, place, cond, action)
1081: Operator op;
1082: Node place;
1083: Node cond;
1084: Command action;
1085: {
1086:     Node event;
1087:     Event e;
1088: 
1089:     if (op == O_STOP) {
1090:     event = build(O_EQ, build(O_SYM, linesym), place);
1091:     } else {
1092:     event = build(O_EQ, build(O_SYM, pcsym), place);
1093:     }
1094:     e = addevent(event, buildcmdlist(action));
1095:     if (isstdin()) {
1096:     printevent(e);
1097:     }
1098: }
1099: 
1100: /*
1101:  * Implement stopping on assignment to a variable by adding it to
1102:  * the variable list.
1103:  */
1104: 
1105: private stopvar(op, exp, place, cond)
1106: Operator op;
1107: Node exp;
1108: Node place;
1109: Node cond;
1110: {
1111:     Symbol p;
1112:     Node event;
1113:     Command action;
1114: 
1115:     if (place == nil) {
1116:     if (exp->op == O_LCON) {
1117:         p = program;
1118:     } else {
1119:         p = tcontainer(exp);
1120:         if (p == nil) {
1121:         p = program;
1122:         }
1123:     }
1124:     } else {
1125:     p = place->value.sym;
1126:     }
1127:     action = build(O_STOPIFCHANGED, exp);
1128:     if (cond != nil) {
1129:     action = build(O_IF, cond, buildcmdlist(action));
1130:     }
1131:     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
1132:     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
1133:     action->value.trace.event = addevent(event, buildcmdlist(action));
1134:     if (isstdin()) {
1135:     printevent(action->value.trace.event);
1136:     }
1137: }
1138: 
1139: /*
1140:  * Assign the value of an expression to a variable (or term).
1141:  */
1142: 
1143: public assign(var, exp)
1144: Node var;
1145: Node exp;
1146: {
1147:     Address addr;
1148:     integer varsize, expsize;
1149:     char cvalue;
1150:     short svalue;
1151:     long lvalue;
1152:     float fvalue;
1153: 
1154:     if (var->op == O_SYM and regnum(var->value.sym) != -1) {
1155:     eval(exp);
1156:     setreg(regnum(var->value.sym), pop(Address));
1157:     } else {
1158:     addr = lval(var);
1159:     varsize = size(var->nodetype);
1160:     expsize = size(exp->nodetype);
1161:     eval(exp);
1162:     if (varsize == sizeof(float) and expsize == sizeof(double)) {
1163:         fvalue = (float) pop(double);
1164:         dwrite(&fvalue, addr, sizeof(fvalue));
1165:     } else {
1166:         if (varsize < sizeof(long)) {
1167:         lvalue = 0;
1168:         popn(expsize, &lvalue);
1169:         if (varsize == sizeof(char)) {
1170:             cvalue = lvalue;
1171:             dwrite(&cvalue, addr, sizeof(cvalue));
1172:         } else if (varsize == sizeof(short)) {
1173:             svalue = lvalue;
1174:             dwrite(&svalue, addr, sizeof(svalue));
1175:         } else {
1176:             error("[internal error: bad size %d in assign]", varsize);
1177:         }
1178:         } else {
1179:         if (expsize <= varsize) {
1180:             sp -= expsize;
1181:             dwrite(sp, addr, expsize);
1182:         } else {
1183:             sp -= expsize;
1184:             dwrite(sp, addr, varsize);
1185:         }
1186:         }
1187:     }
1188:     }
1189: }
1190: 
1191: /*
1192:  * Set a debugger variable.
1193:  */
1194: 
1195: private set (var, exp)
1196: Node var, exp;
1197: {
1198:     Symbol t;
1199: 
1200:     if (var == nil) {
1201:     defvar(nil, nil);
1202:     } else if (exp == nil) {
1203:     defvar(var->value.name, nil);
1204:     } else if (var->value.name == identname("$frame", true)) {
1205:     t = exp->nodetype;
1206:     if (not compatible(t, t_int) and not compatible(t, t_addr)) {
1207:         error("$frame must be an address");
1208:     }
1209:     eval(exp);
1210:     getnewregs(pop(Address));
1211:     } else {
1212:     defvar(var->value.name, unrval(exp));
1213:     }
1214: }
1215: 
1216: /*
1217:  * Execute a list command.
1218:  */
1219: 
1220: private list (p)
1221: Node p;
1222: {
1223:     Symbol f;
1224:     Address addr;
1225:     Lineno line, l1, l2;
1226: 
1227:     if (p->value.arg[0]->op == O_SYM) {
1228:     f = p->value.arg[0]->value.sym;
1229:     addr = firstline(f);
1230:     if (addr == NOADDR) {
1231:         error("no source lines for \"%s\"", symname(f));
1232:     }
1233:     setsource(srcfilename(addr));
1234:     line = srcline(addr);
1235:     getsrcwindow(line, &l1, &l2);
1236:     } else {
1237:     eval(p->value.arg[0]);
1238:     l1 = (Lineno) (pop(long));
1239:     eval(p->value.arg[1]);
1240:     l2 = (Lineno) (pop(long));
1241:     }
1242:     printlines(l1, l2);
1243: }
1244: 
1245: /*
1246:  * Execute a func command.
1247:  */
1248: 
1249: private func (p)
1250: Node p;
1251: {
1252:     Symbol s, f;
1253:     Address addr;
1254: 
1255:     if (p == nil) {
1256:     printname(stdout, curfunc);
1257:     putchar('\n');
1258:     } else {
1259:     s = p->value.sym;
1260:     if (isroutine(s)) {
1261:         setcurfunc(s);
1262:     } else {
1263:         find(f, s->name) where isroutine(f) endfind(f);
1264:         if (f == nil) {
1265:         error("%s is not a procedure or function", symname(s));
1266:         }
1267:         setcurfunc(f);
1268:     }
1269:     addr = codeloc(curfunc);
1270:     if (addr != NOADDR) {
1271:         setsource(srcfilename(addr));
1272:         cursrcline = srcline(addr);
1273:     }
1274:     }
1275: }
1276: 
1277: /*
1278:  * Send a message to the current support person.
1279:  */
1280: 
1281: #ifdef MAINTAINER
1282: static char maintainer[] = MAINTAINER;
1283: #else
1284: static char maintainer[] = "";
1285: #endif
1286: 
1287: public gripe()
1288: {
1289:     typedef Operation();
1290:     Operation *old;
1291:     int pid, status;
1292:     extern int versionNumber;
1293:     char subject[100];
1294: 
1295:     if (maintainer[0] == '\0') {
1296:     puts("Gripes not supported at this site.  Sorry.");
1297:     return;
1298:     }
1299:     puts("Type control-D to end your message.  Be sure to include");
1300:     puts("your name and the name of the file you are debugging.");
1301:     putchar('\n');
1302:     old = signal(SIGINT, SIG_DFL);
1303:     sprintf(subject, "dbx (version 3.%d) gripe", versionNumber);
1304:     pid = back("Mail", stdin, stdout, "-s", subject, maintainer, nil);
1305:     signal(SIGINT, SIG_IGN);
1306:     pwait(pid, &status);
1307:     signal(SIGINT, old);
1308:     if (status == 0) {
1309:     puts("Thank you.");
1310:     } else {
1311:     puts("\nMail not sent.");
1312:     }
1313: }
1314: 
1315: /*
1316:  * Give the user some help.
1317:  */
1318: 
1319: public help()
1320: {
1321:     puts("run                    - begin execution of the program");
1322:     puts("print <exp>            - print the value of the expression");
1323:     puts("where                  - print currently active procedures");
1324:     puts("stop at <line>         - suspend execution at the line");
1325:     puts("stop in <proc>         - suspend execution when <proc> is called");
1326:     puts("cont                   - continue execution");
1327:     puts("step                   - single step one line");
1328:     puts("next                   - step to next line (skip over calls)");
1329:     puts("trace <line#>          - trace execution of the line");
1330:     puts("trace <proc>           - trace calls to the procedure");
1331:     puts("trace <var>            - trace changes to the variable");
1332:     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
1333:     puts("status                 - print trace/stop's in effect");
1334:     puts("delete <number>        - remove trace or stop of given number");
1335:     puts("call <proc>            - call a procedure in program");
1336:     puts("whatis <name>          - print the declaration of the name");
1337:     puts("list <line>, <line>    - list source lines");
1338:     puts("gripe                  - send mail to the person in charge of dbx");
1339:     puts("quit                   - exit dbx");
1340: }
1341: 
1342: /*
1343:  * Divert output to the given file name.
1344:  * Cannot redirect to an existing file.
1345:  */
1346: 
1347: private int so_fd;
1348: private Boolean notstdout;
1349: 
1350: public setout(filename)
1351: String filename;
1352: {
1353:     File f;
1354: 
1355:     f = fopen(filename, "r");
1356:     if (f != nil) {
1357:     fclose(f);
1358:     error("%s: file already exists", filename);
1359:     } else {
1360:     so_fd = dup(1);
1361:     close(1);
1362:     if (creat(filename, 0666) == nil) {
1363:         unsetout();
1364:         error("can't create %s", filename);
1365:     }
1366:     notstdout = true;
1367:     }
1368: }
1369: 
1370: /*
1371:  * Revert output to standard output.
1372:  */
1373: 
1374: public unsetout()
1375: {
1376:     fflush(stdout);
1377:     close(1);
1378:     if (dup(so_fd) != 1) {
1379:     panic("standard out dup failed");
1380:     }
1381:     close(so_fd);
1382:     notstdout = false;
1383: }
1384: 
1385: /*
1386:  * Determine is standard output is currently being redirected
1387:  * to a file (as far as we know).
1388:  */
1389: 
1390: public Boolean isredirected()
1391: {
1392:     return notstdout;
1393: }

Defined functions

assign defined in line 1143; used 1 times
canpush defined in line 733; used 3 times
cond defined in line 804; used 44 times
evalcmdlist defined in line 701; used 5 times
func defined in line 1249; used 1 times
gripe defined in line 1287; used 1 times
help defined in line 1319; used 1 times
list defined in line 1220; used 1 times
lval defined in line 822; used 3 times
popsmall defined in line 773; used 5 times
pushsmall defined in line 743; used 1 times
rpush defined in line 716; used 6 times
set defined in line 1195; used 1 times
setout defined in line 1350; used 2 times
stop defined in line 1038; used 1 times
stopinst defined in line 1080; used 1 times
stopvar defined in line 1105; used 1 times
topeval defined in line 92; used 3 times
trace defined in line 838; used 11 times
traceall defined in line 870; used 1 times
traceat defined in line 934; used 1 times
tracedata defined in line 1008; used 1 times
traceinst defined in line 901; used 1 times
traceproc defined in line 977; used 1 times
unsetout defined in line 1374; used 4 times

Defined variables

maintainer defined in line 1284; used 2 times
rcsid defined in line 11; never used
sccsid defined in line 8; never used
so_fd defined in line 1347; used 3 times
sp defined in line 61; used 18 times
stack defined in line 60; used 3 times

Defined typedef's

Stack defined in line 39; used 3 times

Defined macros

Boolrep defined in line 84; used 13 times
STACKSIZE defined in line 37; used 2 times
alignstack defined in line 54; never used
chksp defined in line 64; used 1 times
pop defined in line 45; used 19 times
poparg defined in line 71; used 3 times
popn defined in line 49; used 1 times
push defined in line 41; used 32 times
Last modified: 1985-06-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2904
Valid CSS Valid XHTML 1.0 Strict