121601Sdist /* 2*38105Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*38105Sbostic * All rights reserved. 4*38105Sbostic * 5*38105Sbostic * Redistribution and use in source and binary forms are permitted 6*38105Sbostic * provided that the above copyright notice and this paragraph are 7*38105Sbostic * duplicated in all such forms and that any documentation, 8*38105Sbostic * advertising materials, and other materials related to such 9*38105Sbostic * distribution and use acknowledge that the software was developed 10*38105Sbostic * by the University of California, Berkeley. The name of the 11*38105Sbostic * University may not be used to endorse or promote products derived 12*38105Sbostic * from this software without specific prior written permission. 13*38105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38105Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621601Sdist */ 179662Slinton 1821601Sdist #ifndef lint 19*38105Sbostic static char sccsid[] = "@(#)eval.c 5.6 (Berkeley) 05/23/89"; 20*38105Sbostic #endif /* not lint */ 219662Slinton 229662Slinton /* 239662Slinton * Tree evaluation. 249662Slinton */ 259662Slinton 269662Slinton #include "defs.h" 279662Slinton #include "tree.h" 289662Slinton #include "operators.h" 2918217Slinton #include "debug.h" 309662Slinton #include "eval.h" 319662Slinton #include "events.h" 329662Slinton #include "symbols.h" 339662Slinton #include "scanner.h" 349662Slinton #include "source.h" 359662Slinton #include "object.h" 369662Slinton #include "mappings.h" 379662Slinton #include "process.h" 3816608Ssam #include "runtime.h" 399662Slinton #include "machine.h" 409662Slinton #include <signal.h> 419662Slinton 429662Slinton #ifndef public 439662Slinton 449662Slinton #include "machine.h" 459662Slinton 4612538Scsvaf #define STACKSIZE 20000 479662Slinton 489662Slinton typedef Char Stack; 499662Slinton 509662Slinton #define push(type, value) { \ 519662Slinton ((type *) (sp += sizeof(type)))[-1] = (value); \ 529662Slinton } 539662Slinton 549662Slinton #define pop(type) ( \ 559662Slinton (*((type *) (sp -= sizeof(type)))) \ 569662Slinton ) 579662Slinton 5816608Ssam #define popn(n, dest) { \ 5916608Ssam sp -= n; \ 6016608Ssam bcopy(sp, dest, n); \ 6116608Ssam } 6216608Ssam 639662Slinton #define alignstack() { \ 649662Slinton sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \ 659662Slinton } 669662Slinton 679662Slinton #endif 689662Slinton 699662Slinton public Stack stack[STACKSIZE]; 709662Slinton public Stack *sp = &stack[0]; 7114674Slinton public Boolean useInstLoc = false; 729662Slinton 739662Slinton #define chksp() \ 749662Slinton { \ 759662Slinton if (sp < &stack[0]) { \ 769662Slinton panic("stack underflow"); \ 779662Slinton } \ 789662Slinton } 799662Slinton 809662Slinton #define poparg(n, r, fr) { \ 819662Slinton eval(p->value.arg[n]); \ 829662Slinton if (isreal(p->op)) { \ 8316608Ssam if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \ 8416608Ssam fr = pop(float); \ 8516608Ssam } else { \ 8616608Ssam fr = pop(double); \ 8716608Ssam } \ 889662Slinton } else if (isint(p->op)) { \ 899662Slinton r = popsmall(p->value.arg[n]->nodetype); \ 909662Slinton } \ 919662Slinton } 929662Slinton 939662Slinton #define Boolrep char /* underlying representation type for booleans */ 949662Slinton 959662Slinton /* 9618217Slinton * Command-level evaluation. 9718217Slinton */ 9818217Slinton 9918217Slinton public Node topnode; 10018217Slinton 10118217Slinton public topeval (p) 10218217Slinton Node p; 10318217Slinton { 10418217Slinton if (traceeval) { 10518217Slinton fprintf(stderr, "topeval("); 10618217Slinton prtree(stderr, p); 10718217Slinton fprintf(stderr, ")\n"); 10818217Slinton fflush(stderr); 10918217Slinton } 11018217Slinton topnode = p; 11118217Slinton eval(p); 11218217Slinton } 11318217Slinton 11418217Slinton /* 1159662Slinton * Evaluate a parse tree leaving the value on the top of the stack. 1169662Slinton */ 1179662Slinton 1189662Slinton public eval(p) 1199662Slinton register Node p; 1209662Slinton { 1219662Slinton long r0, r1; 1229662Slinton double fr0, fr1; 1239662Slinton Address addr; 1249662Slinton long i, n; 1259662Slinton int len; 12618217Slinton Symbol s; 1279662Slinton Node n1, n2; 12818217Slinton boolean b; 1299662Slinton File file; 13018217Slinton String str; 1319662Slinton 1329662Slinton checkref(p); 13318217Slinton if (traceeval) { 13418217Slinton fprintf(stderr, "begin eval %s\n", opname(p->op)); 13512538Scsvaf } 1369662Slinton switch (degree(p->op)) { 1379662Slinton case BINARY: 1389662Slinton poparg(1, r1, fr1); 1399662Slinton poparg(0, r0, fr0); 1409662Slinton break; 1419662Slinton 1429662Slinton case UNARY: 1439662Slinton poparg(0, r0, fr0); 1449662Slinton break; 1459662Slinton 1469662Slinton default: 1479662Slinton /* do nothing */; 1489662Slinton } 1499662Slinton switch (p->op) { 1509662Slinton case O_SYM: 1519662Slinton s = p->value.sym; 1529662Slinton if (s == retaddrsym) { 1539662Slinton push(long, return_addr()); 15418217Slinton } else if (isvariable(s)) { 15518217Slinton if (s != program and not isactive(container(s))) { 15618217Slinton error("\"%s\" is not active", symname(s)); 15718217Slinton } 15818217Slinton if (isvarparam(s) and not isopenarray(s)) { 15918217Slinton rpush(address(s, nil), sizeof(Address)); 1609662Slinton } else { 16118217Slinton push(Address, address(s, nil)); 1629662Slinton } 16318217Slinton } else if (isblock(s)) { 16418217Slinton push(Symbol, s); 16518217Slinton } else if (isconst(s)) { 16618217Slinton eval(constval(s)); 16718217Slinton } else { 16818217Slinton error("can't evaluate a %s", classname(s)); 1699662Slinton } 1709662Slinton break; 1719662Slinton 1729662Slinton case O_LCON: 17318217Slinton case O_CCON: 1749662Slinton r0 = p->value.lcon; 1759662Slinton pushsmall(p->nodetype, r0); 1769662Slinton break; 1779662Slinton 1789662Slinton case O_FCON: 1799662Slinton push(double, p->value.fcon); 1809662Slinton break; 1819662Slinton 1829662Slinton case O_SCON: 1839662Slinton len = size(p->nodetype); 1849662Slinton mov(p->value.scon, sp, len); 1859662Slinton sp += len; 1869662Slinton break; 1879662Slinton 1889662Slinton case O_INDEX: 18918217Slinton s = p->value.arg[0]->nodetype; 19018217Slinton p->value.arg[0]->nodetype = t_addr; 19118217Slinton eval(p->value.arg[0]); 19218217Slinton p->value.arg[0]->nodetype = s; 19318217Slinton n = pop(Address); 19418217Slinton eval(p->value.arg[1]); 19518217Slinton evalindex(s, n, popsmall(p->value.arg[1]->nodetype)); 1969662Slinton break; 1979662Slinton 1989662Slinton case O_DOT: 1999662Slinton s = p->value.arg[1]->value.sym; 20018217Slinton eval(p->value.arg[0]); 20118217Slinton n = pop(long); 2029662Slinton push(long, n + (s->symvalue.field.offset div 8)); 2039662Slinton break; 2049662Slinton 2059662Slinton /* 2069662Slinton * Get the value of the expression addressed by the top of the stack. 2079662Slinton * Push the result back on the stack. 2089662Slinton */ 2099662Slinton 2109662Slinton case O_INDIR: 2119662Slinton case O_RVAL: 2129662Slinton addr = pop(long); 2139662Slinton if (addr == 0) { 2149662Slinton error("reference through nil pointer"); 2159662Slinton } 21618217Slinton len = size(p->nodetype); 2179662Slinton rpush(addr, len); 2189662Slinton break; 2199662Slinton 22011175Slinton case O_TYPERENAME: 22133315Sdonn loophole(size(p->value.arg[0]->nodetype), size(p->nodetype)); 22211175Slinton break; 22311175Slinton 2249662Slinton case O_COMMA: 22518217Slinton eval(p->value.arg[0]); 22618217Slinton if (p->value.arg[1] != nil) { 22718217Slinton eval(p->value.arg[1]); 22818217Slinton } 2299662Slinton break; 2309662Slinton 2319662Slinton case O_ITOF: 2329662Slinton push(double, (double) r0); 2339662Slinton break; 2349662Slinton 2359662Slinton case O_ADD: 2369662Slinton push(long, r0+r1); 2379662Slinton break; 2389662Slinton 2399662Slinton case O_ADDF: 2409662Slinton push(double, fr0+fr1); 2419662Slinton break; 2429662Slinton 2439662Slinton case O_SUB: 2449662Slinton push(long, r0-r1); 2459662Slinton break; 2469662Slinton 2479662Slinton case O_SUBF: 2489662Slinton push(double, fr0-fr1); 2499662Slinton break; 2509662Slinton 2519662Slinton case O_NEG: 2529662Slinton push(long, -r0); 2539662Slinton break; 2549662Slinton 2559662Slinton case O_NEGF: 2569662Slinton push(double, -fr0); 2579662Slinton break; 2589662Slinton 2599662Slinton case O_MUL: 2609662Slinton push(long, r0*r1); 2619662Slinton break; 2629662Slinton 2639662Slinton case O_MULF: 2649662Slinton push(double, fr0*fr1); 2659662Slinton break; 2669662Slinton 2679662Slinton case O_DIVF: 2689662Slinton if (fr1 == 0) { 2699662Slinton error("error: division by 0"); 2709662Slinton } 2719662Slinton push(double, fr0 / fr1); 2729662Slinton break; 2739662Slinton 2749662Slinton case O_DIV: 2759662Slinton if (r1 == 0) { 2769662Slinton error("error: div by 0"); 2779662Slinton } 2789662Slinton push(long, r0 div r1); 2799662Slinton break; 2809662Slinton 2819662Slinton case O_MOD: 2829662Slinton if (r1 == 0) { 2839662Slinton error("error: mod by 0"); 2849662Slinton } 2859662Slinton push(long, r0 mod r1); 2869662Slinton break; 2879662Slinton 2889662Slinton case O_LT: 2899662Slinton push(Boolrep, r0 < r1); 2909662Slinton break; 2919662Slinton 2929662Slinton case O_LTF: 2939662Slinton push(Boolrep, fr0 < fr1); 2949662Slinton break; 2959662Slinton 2969662Slinton case O_LE: 2979662Slinton push(Boolrep, r0 <= r1); 2989662Slinton break; 2999662Slinton 3009662Slinton case O_LEF: 3019662Slinton push(Boolrep, fr0 <= fr1); 3029662Slinton break; 3039662Slinton 3049662Slinton case O_GT: 3059662Slinton push(Boolrep, r0 > r1); 3069662Slinton break; 3079662Slinton 3089662Slinton case O_GTF: 3099662Slinton push(Boolrep, fr0 > fr1); 3109662Slinton break; 3119662Slinton 3129662Slinton case O_EQ: 3139662Slinton push(Boolrep, r0 == r1); 3149662Slinton break; 3159662Slinton 3169662Slinton case O_EQF: 3179662Slinton push(Boolrep, fr0 == fr1); 3189662Slinton break; 3199662Slinton 3209662Slinton case O_NE: 3219662Slinton push(Boolrep, r0 != r1); 3229662Slinton break; 3239662Slinton 3249662Slinton case O_NEF: 3259662Slinton push(Boolrep, fr0 != fr1); 3269662Slinton break; 3279662Slinton 3289662Slinton case O_AND: 3299662Slinton push(Boolrep, r0 and r1); 3309662Slinton break; 3319662Slinton 3329662Slinton case O_OR: 3339662Slinton push(Boolrep, r0 or r1); 3349662Slinton break; 3359662Slinton 3369662Slinton case O_ASSIGN: 3379662Slinton assign(p->value.arg[0], p->value.arg[1]); 3389662Slinton break; 3399662Slinton 3409662Slinton case O_CHFILE: 3419662Slinton if (p->value.scon == nil) { 3429662Slinton printf("%s\n", cursource); 3439662Slinton } else { 3449662Slinton file = opensource(p->value.scon); 3459662Slinton if (file == nil) { 3469662Slinton error("can't read \"%s\"", p->value.scon); 3479662Slinton } else { 3489662Slinton fclose(file); 3499662Slinton setsource(p->value.scon); 3509662Slinton } 3519662Slinton } 3529662Slinton break; 3539662Slinton 3549662Slinton case O_CONT: 35511871Slinton cont(p->value.lcon); 3569662Slinton printnews(); 3579662Slinton break; 3589662Slinton 3599662Slinton case O_LIST: 36018217Slinton list(p); 3619662Slinton break; 3629662Slinton 3639662Slinton case O_FUNC: 36418217Slinton func(p->value.arg[0]); 3659662Slinton break; 3669662Slinton 3679662Slinton case O_EXAMINE: 3689662Slinton eval(p->value.examine.beginaddr); 3699662Slinton r0 = pop(long); 3709662Slinton if (p->value.examine.endaddr == nil) { 3719662Slinton n = p->value.examine.count; 37211175Slinton if (n == 0) { 37311175Slinton printvalue(r0, p->value.examine.mode); 37411175Slinton } else if (streq(p->value.examine.mode, "i")) { 3759662Slinton printninst(n, (Address) r0); 3769662Slinton } else { 3779662Slinton printndata(n, (Address) r0, p->value.examine.mode); 3789662Slinton } 3799662Slinton } else { 3809662Slinton eval(p->value.examine.endaddr); 3819662Slinton r1 = pop(long); 3829662Slinton if (streq(p->value.examine.mode, "i")) { 3839662Slinton printinst((Address)r0, (Address)r1); 3849662Slinton } else { 3859662Slinton printdata((Address)r0, (Address)r1, p->value.examine.mode); 3869662Slinton } 3879662Slinton } 3889662Slinton break; 3899662Slinton 3909662Slinton case O_PRINT: 3919662Slinton for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 3929662Slinton eval(n1->value.arg[0]); 3939662Slinton printval(n1->value.arg[0]->nodetype); 3949662Slinton putchar(' '); 3959662Slinton } 3969662Slinton putchar('\n'); 3979662Slinton break; 3989662Slinton 3999662Slinton case O_PSYM: 4009662Slinton if (p->value.arg[0]->op == O_SYM) { 4019662Slinton psym(p->value.arg[0]->value.sym); 4029662Slinton } else { 4039662Slinton psym(p->value.arg[0]->nodetype); 4049662Slinton } 4059662Slinton break; 4069662Slinton 4079662Slinton case O_QLINE: 4089662Slinton eval(p->value.arg[1]); 4099662Slinton break; 4109662Slinton 4119662Slinton case O_STEP: 4129662Slinton b = inst_tracing; 4139662Slinton inst_tracing = (Boolean) (not p->value.step.source); 4149662Slinton if (p->value.step.skipcalls) { 4159662Slinton next(); 4169662Slinton } else { 4179662Slinton stepc(); 4189662Slinton } 4199662Slinton inst_tracing = b; 42014674Slinton useInstLoc = (Boolean) (not p->value.step.source); 4219662Slinton printnews(); 4229662Slinton break; 4239662Slinton 4249662Slinton case O_WHATIS: 4259662Slinton if (p->value.arg[0]->op == O_SYM) { 4269662Slinton printdecl(p->value.arg[0]->value.sym); 4279662Slinton } else { 4289662Slinton printdecl(p->value.arg[0]->nodetype); 4299662Slinton } 4309662Slinton break; 4319662Slinton 4329662Slinton case O_WHERE: 4339662Slinton wherecmd(); 4349662Slinton break; 4359662Slinton 4369662Slinton case O_WHEREIS: 43712538Scsvaf if (p->value.arg[0]->op == O_SYM) { 43818217Slinton printwhereis(stdout, p->value.arg[0]->value.sym); 43912538Scsvaf } else { 44018217Slinton printwhereis(stdout, p->value.arg[0]->nodetype); 44112538Scsvaf } 4429662Slinton break; 4439662Slinton 4449662Slinton case O_WHICH: 44512538Scsvaf if (p->value.arg[0]->op == O_SYM) { 44618217Slinton printwhich(stdout, p->value.arg[0]->value.sym); 44712538Scsvaf } else { 44818217Slinton printwhich(stdout, p->value.arg[0]->nodetype); 44912538Scsvaf } 4509662Slinton putchar('\n'); 4519662Slinton break; 4529662Slinton 4539662Slinton case O_ALIAS: 4549662Slinton n1 = p->value.arg[0]; 4559662Slinton n2 = p->value.arg[1]; 45618217Slinton if (n2 == nil) { 45718217Slinton if (n1 == nil) { 45818217Slinton alias(nil, nil, nil); 45918217Slinton } else { 46018217Slinton alias(n1->value.name, nil, nil); 46118217Slinton } 46218217Slinton } else if (n2->op == O_NAME) { 46318217Slinton str = ident(n2->value.name); 46418217Slinton alias(n1->value.name, nil, strdup(str)); 4659662Slinton } else { 46618217Slinton if (n1->op == O_COMMA) { 46718217Slinton alias( 46818217Slinton n1->value.arg[0]->value.name, 46918217Slinton (List) n1->value.arg[1], 47018217Slinton n2->value.scon 47118217Slinton ); 47218217Slinton } else { 47318217Slinton alias(n1->value.name, nil, n2->value.scon); 47418217Slinton } 4759662Slinton } 4769662Slinton break; 4779662Slinton 47818217Slinton case O_UNALIAS: 47918217Slinton unalias(p->value.arg[0]->value.name); 48018217Slinton break; 48118217Slinton 48218217Slinton case O_CALLPROC: 48318217Slinton callproc(p, false); 48418217Slinton break; 48518217Slinton 4869662Slinton case O_CALL: 48718217Slinton callproc(p, true); 4889662Slinton break; 4899662Slinton 4909662Slinton case O_CATCH: 49118217Slinton if (p->value.lcon == 0) { 49218217Slinton printsigscaught(process); 49318217Slinton } else { 49418217Slinton psigtrace(process, p->value.lcon, true); 49518217Slinton } 4969662Slinton break; 4979662Slinton 4989662Slinton case O_EDIT: 4999662Slinton edit(p->value.scon); 5009662Slinton break; 5019662Slinton 50212538Scsvaf case O_DEBUG: 50312538Scsvaf debug(p); 50412538Scsvaf break; 50512538Scsvaf 50616608Ssam case O_DOWN: 50716608Ssam checkref(p->value.arg[0]); 50816608Ssam assert(p->value.arg[0]->op == O_LCON); 50916608Ssam down(p->value.arg[0]->value.lcon); 51016608Ssam break; 51116608Ssam 5129662Slinton case O_DUMP: 51318217Slinton if (p->value.arg[0] == nil) { 51418217Slinton dumpall(); 51518217Slinton } else { 51618217Slinton s = p->value.arg[0]->value.sym; 51718217Slinton if (s == curfunc) { 51818217Slinton dump(nil); 51918217Slinton } else { 52018217Slinton dump(s); 52118217Slinton } 52218217Slinton } 5239662Slinton break; 5249662Slinton 5259662Slinton case O_GRIPE: 5269662Slinton gripe(); 5279662Slinton break; 5289662Slinton 5299662Slinton case O_HELP: 5309662Slinton help(); 5319662Slinton break; 5329662Slinton 5339662Slinton case O_IGNORE: 53418217Slinton if (p->value.lcon == 0) { 53518217Slinton printsigsignored(process); 53618217Slinton } else { 53718217Slinton psigtrace(process, p->value.lcon, false); 53818217Slinton } 5399662Slinton break; 5409662Slinton 54116608Ssam case O_RETURN: 54216608Ssam if (p->value.arg[0] == nil) { 54316608Ssam rtnfunc(nil); 54416608Ssam } else { 54516608Ssam assert(p->value.arg[0]->op == O_SYM); 54616608Ssam rtnfunc(p->value.arg[0]->value.sym); 54716608Ssam } 54816608Ssam break; 54916608Ssam 5509662Slinton case O_RUN: 5519662Slinton run(); 5529662Slinton break; 5539662Slinton 55418217Slinton case O_SET: 55518217Slinton set(p->value.arg[0], p->value.arg[1]); 55618217Slinton break; 55718217Slinton 55818217Slinton case O_SEARCH: 55918217Slinton search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon); 56018217Slinton break; 56118217Slinton 5629662Slinton case O_SOURCE: 5639662Slinton setinput(p->value.scon); 5649662Slinton break; 5659662Slinton 5669662Slinton case O_STATUS: 5679662Slinton status(); 5689662Slinton break; 5699662Slinton 5709662Slinton case O_TRACE: 5719662Slinton case O_TRACEI: 5729662Slinton trace(p); 5739662Slinton break; 5749662Slinton 5759662Slinton case O_STOP: 5769662Slinton case O_STOPI: 5779662Slinton stop(p); 5789662Slinton break; 5799662Slinton 58018217Slinton case O_UNSET: 58118217Slinton undefvar(p->value.arg[0]->value.name); 58218217Slinton break; 58318217Slinton 58416608Ssam case O_UP: 58516608Ssam checkref(p->value.arg[0]); 58616608Ssam assert(p->value.arg[0]->op == O_LCON); 58716608Ssam up(p->value.arg[0]->value.lcon); 58816608Ssam break; 58916608Ssam 5909662Slinton case O_ADDEVENT: 5919662Slinton addevent(p->value.event.cond, p->value.event.actions); 5929662Slinton break; 5939662Slinton 5949662Slinton case O_DELETE: 59516608Ssam n1 = p->value.arg[0]; 59616608Ssam while (n1->op == O_COMMA) { 59716608Ssam n2 = n1->value.arg[0]; 59816608Ssam assert(n2->op == O_LCON); 59916608Ssam if (not delevent((unsigned int) n2->value.lcon)) { 60016608Ssam error("unknown event %ld", n2->value.lcon); 60116608Ssam } 60216608Ssam n1 = n1->value.arg[1]; 60316608Ssam } 60416608Ssam assert(n1->op == O_LCON); 60516608Ssam if (not delevent((unsigned int) n1->value.lcon)) { 60616608Ssam error("unknown event %ld", n1->value.lcon); 60716608Ssam } 6089662Slinton break; 6099662Slinton 6109662Slinton case O_ENDX: 6119662Slinton endprogram(); 6129662Slinton break; 6139662Slinton 6149662Slinton case O_IF: 6159662Slinton if (cond(p->value.event.cond)) { 6169662Slinton evalcmdlist(p->value.event.actions); 6179662Slinton } 6189662Slinton break; 6199662Slinton 6209662Slinton case O_ONCE: 6219662Slinton event_once(p->value.event.cond, p->value.event.actions); 6229662Slinton break; 6239662Slinton 6249662Slinton case O_PRINTCALL: 6259662Slinton printcall(p->value.sym, whatblock(return_addr())); 6269662Slinton break; 6279662Slinton 6289662Slinton case O_PRINTIFCHANGED: 6299662Slinton printifchanged(p->value.arg[0]); 6309662Slinton break; 6319662Slinton 6329662Slinton case O_PRINTRTN: 6339662Slinton printrtn(p->value.sym); 6349662Slinton break; 6359662Slinton 6369662Slinton case O_PRINTSRCPOS: 6379662Slinton getsrcpos(); 6389662Slinton if (p->value.arg[0] == nil) { 6399662Slinton printsrcpos(); 6409662Slinton putchar('\n'); 6419662Slinton printlines(curline, curline); 6429662Slinton } else if (p->value.arg[0]->op == O_QLINE) { 6439662Slinton if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 6449662Slinton printf("tracei: "); 6459662Slinton printinst(pc, pc); 6469662Slinton } else { 64718217Slinton if (canReadSource()) { 64818217Slinton printf("trace: "); 64918217Slinton printlines(curline, curline); 65018217Slinton } 6519662Slinton } 6529662Slinton } else { 6539662Slinton printsrcpos(); 6549662Slinton printf(": "); 6559662Slinton eval(p->value.arg[0]); 6569662Slinton prtree(stdout, p->value.arg[0]); 6579662Slinton printf(" = "); 6589662Slinton printval(p->value.arg[0]->nodetype); 6599662Slinton putchar('\n'); 6609662Slinton } 6619662Slinton break; 6629662Slinton 6639662Slinton case O_PROCRTN: 6649662Slinton procreturn(p->value.sym); 6659662Slinton break; 6669662Slinton 6679662Slinton case O_STOPIFCHANGED: 6689662Slinton stopifchanged(p->value.arg[0]); 6699662Slinton break; 6709662Slinton 6719662Slinton case O_STOPX: 6729662Slinton isstopped = true; 6739662Slinton break; 6749662Slinton 6759662Slinton case O_TRACEON: 6769662Slinton traceon(p->value.trace.inst, p->value.trace.event, 6779662Slinton p->value.trace.actions); 6789662Slinton break; 6799662Slinton 6809662Slinton case O_TRACEOFF: 6819662Slinton traceoff(p->value.lcon); 6829662Slinton break; 6839662Slinton 6849662Slinton default: 6859662Slinton panic("eval: bad op %d", p->op); 6869662Slinton } 68718217Slinton if (traceeval) { 68818217Slinton fprintf(stderr, "end eval %s\n", opname(p->op)); 68918217Slinton } 6909662Slinton } 6919662Slinton 6929662Slinton /* 6939662Slinton * Evaluate a list of commands. 6949662Slinton */ 6959662Slinton 6969662Slinton public evalcmdlist(cl) 6979662Slinton Cmdlist cl; 6989662Slinton { 6999662Slinton Command c; 7009662Slinton 7019662Slinton foreach (Command, c, cl) 7029662Slinton evalcmd(c); 7039662Slinton endfor 7049662Slinton } 7059662Slinton 7069662Slinton /* 7079662Slinton * Push "len" bytes onto the expression stack from address "addr" 7089662Slinton * in the process. If there isn't room on the stack, print an error message. 7099662Slinton */ 7109662Slinton 7119662Slinton public rpush(addr, len) 7129662Slinton Address addr; 7139662Slinton int len; 7149662Slinton { 7159662Slinton if (not canpush(len)) { 7169662Slinton error("expression too large to evaluate"); 7179662Slinton } else { 7189662Slinton chksp(); 7199662Slinton dread(sp, addr, len); 7209662Slinton sp += len; 7219662Slinton } 7229662Slinton } 7239662Slinton 7249662Slinton /* 7259662Slinton * Check if the stack has n bytes available. 7269662Slinton */ 7279662Slinton 7289662Slinton public Boolean canpush(n) 7299662Slinton Integer n; 7309662Slinton { 7319662Slinton return (Boolean) (sp + n < &stack[STACKSIZE]); 7329662Slinton } 7339662Slinton 7349662Slinton /* 7359662Slinton * Push a small scalar of the given type onto the stack. 7369662Slinton */ 7379662Slinton 7389662Slinton public pushsmall(t, v) 7399662Slinton Symbol t; 7409662Slinton long v; 7419662Slinton { 7429662Slinton register Integer s; 7439662Slinton 7449662Slinton s = size(t); 7459662Slinton switch (s) { 7469662Slinton case sizeof(char): 7479662Slinton push(char, v); 7489662Slinton break; 7499662Slinton 7509662Slinton case sizeof(short): 7519662Slinton push(short, v); 7529662Slinton break; 7539662Slinton 7549662Slinton case sizeof(long): 7559662Slinton push(long, v); 7569662Slinton break; 7579662Slinton 7589662Slinton default: 7599662Slinton panic("bad size %d in popsmall", s); 7609662Slinton } 7619662Slinton } 7629662Slinton 7639662Slinton /* 7649662Slinton * Pop an item of the given type which is assumed to be no larger 7659662Slinton * than a long and return it expanded into a long. 7669662Slinton */ 7679662Slinton 7689662Slinton public long popsmall(t) 7699662Slinton Symbol t; 7709662Slinton { 77118217Slinton register integer n; 7729662Slinton long r; 7739662Slinton 77418217Slinton n = size(t); 77518217Slinton if (n == sizeof(char)) { 77618217Slinton if (t->class == RANGE and t->symvalue.rangev.lower >= 0) { 77718217Slinton r = (long) pop(unsigned char); 77818217Slinton } else { 7799662Slinton r = (long) pop(char); 78018217Slinton } 78118217Slinton } else if (n == sizeof(short)) { 78218217Slinton if (t->class == RANGE and t->symvalue.rangev.lower >= 0) { 78318217Slinton r = (long) pop(unsigned short); 78418217Slinton } else { 7859662Slinton r = (long) pop(short); 78618217Slinton } 78718217Slinton } else if (n == sizeof(long)) { 78818217Slinton r = pop(long); 78918217Slinton } else { 79018217Slinton error("[internal error: size %d in popsmall]", n); 7919662Slinton } 7929662Slinton return r; 7939662Slinton } 7949662Slinton 7959662Slinton /* 7969662Slinton * Evaluate a conditional expression. 7979662Slinton */ 7989662Slinton 7999662Slinton public Boolean cond(p) 8009662Slinton Node p; 8019662Slinton { 80233315Sdonn Boolean b; 80333315Sdonn int i; 8049662Slinton 8059662Slinton if (p == nil) { 8069662Slinton b = true; 8079662Slinton } else { 8089662Slinton eval(p); 80933315Sdonn i = pop(Boolrep); 81033315Sdonn b = (Boolean) i; 8119662Slinton } 8129662Slinton return b; 8139662Slinton } 8149662Slinton 8159662Slinton /* 8169662Slinton * Return the address corresponding to a given tree. 8179662Slinton */ 8189662Slinton 8199662Slinton public Address lval(p) 8209662Slinton Node p; 8219662Slinton { 8229662Slinton if (p->op == O_RVAL) { 8239662Slinton eval(p->value.arg[0]); 8249662Slinton } else { 8259662Slinton eval(p); 8269662Slinton } 8279662Slinton return (Address) (pop(long)); 8289662Slinton } 8299662Slinton 8309662Slinton /* 8319662Slinton * Process a trace command, translating into the appropriate events 8329662Slinton * and associated actions. 8339662Slinton */ 8349662Slinton 8359662Slinton public trace(p) 8369662Slinton Node p; 8379662Slinton { 8389662Slinton Node exp, place, cond; 8399662Slinton Node left; 8409662Slinton 8419662Slinton exp = p->value.arg[0]; 8429662Slinton place = p->value.arg[1]; 8439662Slinton cond = p->value.arg[2]; 8449662Slinton if (exp == nil) { 8459662Slinton traceall(p->op, place, cond); 84611771Slinton } else if (exp->op == O_QLINE or exp->op == O_LCON) { 8479662Slinton traceinst(p->op, exp, cond); 8489662Slinton } else if (place != nil and place->op == O_QLINE) { 8499662Slinton traceat(p->op, exp, place, cond); 8509662Slinton } else { 8519861Slinton left = exp; 8529861Slinton if (left->op == O_RVAL or left->op == O_CALL) { 8539861Slinton left = left->value.arg[0]; 8549861Slinton } 8559662Slinton if (left->op == O_SYM and isblock(left->value.sym)) { 8569662Slinton traceproc(p->op, left->value.sym, place, cond); 8579662Slinton } else { 8589662Slinton tracedata(p->op, exp, place, cond); 8599662Slinton } 8609662Slinton } 8619662Slinton } 8629662Slinton 8639662Slinton /* 8649662Slinton * Set a breakpoint that will turn on tracing. 8659662Slinton */ 8669662Slinton 8679662Slinton private traceall(op, place, cond) 8689662Slinton Operator op; 8699662Slinton Node place; 8709662Slinton Node cond; 8719662Slinton { 8729662Slinton Symbol s; 8739662Slinton Node event; 8749662Slinton Command action; 8759662Slinton 8769662Slinton if (place == nil) { 8779662Slinton s = program; 8789662Slinton } else { 8799662Slinton s = place->value.sym; 8809662Slinton } 8819662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 8829662Slinton action = build(O_PRINTSRCPOS, 8839662Slinton build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 8849662Slinton if (cond != nil) { 8859662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8869662Slinton } 8879662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 8889662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 88911871Slinton if (isstdin()) { 89011871Slinton printevent(action->value.trace.event); 89111871Slinton } 8929662Slinton } 8939662Slinton 8949662Slinton /* 8959662Slinton * Set up the appropriate breakpoint for tracing an instruction. 8969662Slinton */ 8979662Slinton 8989662Slinton private traceinst(op, exp, cond) 8999662Slinton Operator op; 9009662Slinton Node exp; 9019662Slinton Node cond; 9029662Slinton { 90311771Slinton Node event, wh; 9049662Slinton Command action; 90511871Slinton Event e; 9069662Slinton 90711771Slinton if (exp->op == O_LCON) { 90818217Slinton wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp); 90911771Slinton } else { 91011771Slinton wh = exp; 91111771Slinton } 9129662Slinton if (op == O_TRACEI) { 91311771Slinton event = build(O_EQ, build(O_SYM, pcsym), wh); 9149662Slinton } else { 91511771Slinton event = build(O_EQ, build(O_SYM, linesym), wh); 9169662Slinton } 91711771Slinton action = build(O_PRINTSRCPOS, wh); 9189662Slinton if (cond) { 9199662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9209662Slinton } 92111871Slinton e = addevent(event, buildcmdlist(action)); 92211871Slinton if (isstdin()) { 92311871Slinton printevent(e); 92411871Slinton } 9259662Slinton } 9269662Slinton 9279662Slinton /* 9289662Slinton * Set a breakpoint to print an expression at a given line or address. 9299662Slinton */ 9309662Slinton 9319662Slinton private traceat(op, exp, place, cond) 9329662Slinton Operator op; 9339662Slinton Node exp; 9349662Slinton Node place; 9359662Slinton Node cond; 9369662Slinton { 9379662Slinton Node event; 9389662Slinton Command action; 93911871Slinton Event e; 9409662Slinton 9419662Slinton if (op == O_TRACEI) { 9429662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 9439662Slinton } else { 9449662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 9459662Slinton } 9469662Slinton action = build(O_PRINTSRCPOS, exp); 9479662Slinton if (cond != nil) { 9489662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9499662Slinton } 95011871Slinton e = addevent(event, buildcmdlist(action)); 95111871Slinton if (isstdin()) { 95211871Slinton printevent(e); 95311871Slinton } 9549662Slinton } 9559662Slinton 9569662Slinton /* 9579662Slinton * Construct event for tracing a procedure. 9589662Slinton * 9599662Slinton * What we want here is 9609662Slinton * 9619662Slinton * when $proc = p do 9629662Slinton * if <condition> then 9639662Slinton * printcall; 9649662Slinton * once $pc = $retaddr do 9659662Slinton * printrtn; 9669662Slinton * end; 9679662Slinton * end if; 9689662Slinton * end; 9699662Slinton * 9709662Slinton * Note that "once" is like "when" except that the event 9719662Slinton * deletes itself as part of its associated action. 9729662Slinton */ 9739662Slinton 9749662Slinton private traceproc(op, p, place, cond) 9759662Slinton Operator op; 9769662Slinton Symbol p; 9779662Slinton Node place; 9789662Slinton Node cond; 9799662Slinton { 9809662Slinton Node event; 9819662Slinton Command action; 9829662Slinton Cmdlist actionlist; 98311871Slinton Event e; 9849662Slinton 9859662Slinton action = build(O_PRINTCALL, p); 9869662Slinton actionlist = list_alloc(); 9879662Slinton cmdlist_append(action, actionlist); 9889662Slinton event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 9899662Slinton action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 9909662Slinton cmdlist_append(action, actionlist); 9919662Slinton if (cond != nil) { 9929662Slinton actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 9939662Slinton } 9949662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 99511871Slinton e = addevent(event, actionlist); 99611871Slinton if (isstdin()) { 99711871Slinton printevent(e); 99811871Slinton } 9999662Slinton } 10009662Slinton 10019662Slinton /* 10029662Slinton * Set up breakpoint for tracing data. 10039662Slinton */ 10049662Slinton 10059662Slinton private tracedata(op, exp, place, cond) 10069662Slinton Operator op; 10079662Slinton Node exp; 10089662Slinton Node place; 10099662Slinton Node cond; 10109662Slinton { 10119662Slinton Symbol p; 10129662Slinton Node event; 10139662Slinton Command action; 10149662Slinton 101533315Sdonn if (size(exp->nodetype) > MAXTRSIZE) { 101633315Sdonn error("expression too large to trace (limit is %d bytes)", MAXTRSIZE); 101733315Sdonn } 10189662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 10199662Slinton if (p == nil) { 10209662Slinton p = program; 10219662Slinton } 10229662Slinton action = build(O_PRINTIFCHANGED, exp); 10239662Slinton if (cond != nil) { 10249662Slinton action = build(O_IF, cond, buildcmdlist(action)); 10259662Slinton } 10269662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 10279662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 10289662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 102911871Slinton if (isstdin()) { 103011871Slinton printevent(action->value.trace.event); 103111871Slinton } 10329662Slinton } 10339662Slinton 10349662Slinton /* 10359662Slinton * Setting and unsetting of stops. 10369662Slinton */ 10379662Slinton 10389662Slinton public stop(p) 10399662Slinton Node p; 10409662Slinton { 104113846Slinton Node exp, place, cond, t; 10429662Slinton Symbol s; 10439662Slinton Command action; 104411871Slinton Event e; 10459662Slinton 10469662Slinton exp = p->value.arg[0]; 10479662Slinton place = p->value.arg[1]; 10489662Slinton cond = p->value.arg[2]; 10499662Slinton if (exp != nil) { 10509662Slinton stopvar(p->op, exp, place, cond); 105113846Slinton } else { 105213846Slinton action = build(O_STOPX); 105313846Slinton if (cond != nil) { 105413846Slinton action = build(O_IF, cond, buildcmdlist(action)); 105511871Slinton } 105616608Ssam if (place == nil or place->op == O_SYM) { 105716608Ssam if (place == nil) { 105816608Ssam s = program; 105916608Ssam } else { 106016608Ssam s = place->value.sym; 106116608Ssam } 106213846Slinton t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 106313846Slinton if (cond != nil) { 106413846Slinton action = build(O_TRACEON, (p->op == O_STOPI), 106513846Slinton buildcmdlist(action)); 106613846Slinton e = addevent(t, buildcmdlist(action)); 106713846Slinton action->value.trace.event = e; 106813846Slinton } else { 106913846Slinton e = addevent(t, buildcmdlist(action)); 107013846Slinton } 107113846Slinton if (isstdin()) { 107213846Slinton printevent(e); 107313846Slinton } 107413846Slinton } else { 107513846Slinton stopinst(p->op, place, cond, action); 107613846Slinton } 10779662Slinton } 10789662Slinton } 10799662Slinton 108013846Slinton private stopinst(op, place, cond, action) 10819662Slinton Operator op; 10829662Slinton Node place; 10839662Slinton Node cond; 108413846Slinton Command action; 10859662Slinton { 10869662Slinton Node event; 108711871Slinton Event e; 10889662Slinton 10899662Slinton if (op == O_STOP) { 10909662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 10919662Slinton } else { 10929662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 10939662Slinton } 109413846Slinton e = addevent(event, buildcmdlist(action)); 109511871Slinton if (isstdin()) { 109611871Slinton printevent(e); 109711871Slinton } 10989662Slinton } 10999662Slinton 11009662Slinton /* 11019662Slinton * Implement stopping on assignment to a variable by adding it to 11029662Slinton * the variable list. 11039662Slinton */ 11049662Slinton 11059662Slinton private stopvar(op, exp, place, cond) 11069662Slinton Operator op; 11079662Slinton Node exp; 11089662Slinton Node place; 11099662Slinton Node cond; 11109662Slinton { 11119662Slinton Symbol p; 11129662Slinton Node event; 11139662Slinton Command action; 11149662Slinton 111533315Sdonn if (size(exp->nodetype) > MAXTRSIZE) { 111633315Sdonn error("expression too large to trace (limit is %d bytes)", MAXTRSIZE); 111733315Sdonn } 111814445Slinton if (place == nil) { 111914445Slinton if (exp->op == O_LCON) { 112014445Slinton p = program; 112114445Slinton } else { 112214445Slinton p = tcontainer(exp); 112314445Slinton if (p == nil) { 112414445Slinton p = program; 112514445Slinton } 112614445Slinton } 112714445Slinton } else { 112814445Slinton p = place->value.sym; 11299662Slinton } 113014445Slinton action = build(O_STOPIFCHANGED, exp); 113114445Slinton if (cond != nil) { 113214445Slinton action = build(O_IF, cond, buildcmdlist(action)); 113314445Slinton } 11349662Slinton action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 11359662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 11369662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 113711871Slinton if (isstdin()) { 113811871Slinton printevent(action->value.trace.event); 113911871Slinton } 11409662Slinton } 11419662Slinton 11429662Slinton /* 11439662Slinton * Assign the value of an expression to a variable (or term). 11449662Slinton */ 11459662Slinton 11469662Slinton public assign(var, exp) 11479662Slinton Node var; 11489662Slinton Node exp; 11499662Slinton { 11509662Slinton Address addr; 115116608Ssam integer varsize, expsize; 11529662Slinton char cvalue; 11539662Slinton short svalue; 11549662Slinton long lvalue; 115516608Ssam float fvalue; 11569662Slinton 115718217Slinton if (var->op == O_SYM and regnum(var->value.sym) != -1) { 115818217Slinton eval(exp); 115918217Slinton setreg(regnum(var->value.sym), pop(Address)); 116016608Ssam } else { 116118217Slinton addr = lval(var); 116218217Slinton varsize = size(var->nodetype); 116318217Slinton expsize = size(exp->nodetype); 116418217Slinton eval(exp); 116518217Slinton if (varsize == sizeof(float) and expsize == sizeof(double)) { 116618217Slinton fvalue = (float) pop(double); 116718217Slinton dwrite(&fvalue, addr, sizeof(fvalue)); 116818217Slinton } else { 116918217Slinton if (varsize < sizeof(long)) { 117018217Slinton lvalue = 0; 117118217Slinton popn(expsize, &lvalue); 117218217Slinton if (varsize == sizeof(char)) { 117316608Ssam cvalue = lvalue; 117416608Ssam dwrite(&cvalue, addr, sizeof(cvalue)); 117518217Slinton } else if (varsize == sizeof(short)) { 117616608Ssam svalue = lvalue; 117716608Ssam dwrite(&svalue, addr, sizeof(svalue)); 117818217Slinton } else { 117918217Slinton error("[internal error: bad size %d in assign]", varsize); 118018217Slinton } 118118217Slinton } else { 118218217Slinton if (expsize <= varsize) { 118318217Slinton sp -= expsize; 118418217Slinton dwrite(sp, addr, expsize); 118518217Slinton } else { 118618217Slinton sp -= expsize; 118718217Slinton dwrite(sp, addr, varsize); 118818217Slinton } 118918217Slinton } 119018217Slinton } 119118217Slinton } 119218217Slinton } 11939662Slinton 119418217Slinton /* 119518217Slinton * Set a debugger variable. 119618217Slinton */ 119718217Slinton 119818217Slinton private set (var, exp) 119918217Slinton Node var, exp; 120018217Slinton { 120118217Slinton Symbol t; 120218217Slinton 120318217Slinton if (var == nil) { 120418217Slinton defvar(nil, nil); 120518217Slinton } else if (exp == nil) { 120618217Slinton defvar(var->value.name, nil); 120718217Slinton } else if (var->value.name == identname("$frame", true)) { 120818217Slinton t = exp->nodetype; 120918217Slinton if (not compatible(t, t_int) and not compatible(t, t_addr)) { 121018217Slinton error("$frame must be an address"); 121118217Slinton } 121218217Slinton eval(exp); 121318217Slinton getnewregs(pop(Address)); 121418217Slinton } else { 121518217Slinton defvar(var->value.name, unrval(exp)); 121618217Slinton } 121718217Slinton } 121818217Slinton 121918217Slinton /* 122018217Slinton * Execute a list command. 122118217Slinton */ 122218217Slinton 122318217Slinton private list (p) 122418217Slinton Node p; 122518217Slinton { 122618217Slinton Symbol f; 122718217Slinton Address addr; 122818217Slinton Lineno line, l1, l2; 122918217Slinton 123018217Slinton if (p->value.arg[0]->op == O_SYM) { 123118217Slinton f = p->value.arg[0]->value.sym; 123218217Slinton addr = firstline(f); 123318217Slinton if (addr == NOADDR) { 123418217Slinton error("no source lines for \"%s\"", symname(f)); 123518217Slinton } 123618217Slinton setsource(srcfilename(addr)); 123718217Slinton line = srcline(addr); 123818217Slinton getsrcwindow(line, &l1, &l2); 123918217Slinton } else { 124018217Slinton eval(p->value.arg[0]); 124118217Slinton l1 = (Lineno) (pop(long)); 124218217Slinton eval(p->value.arg[1]); 124318217Slinton l2 = (Lineno) (pop(long)); 124418217Slinton } 124518217Slinton printlines(l1, l2); 124618217Slinton } 124718217Slinton 124818217Slinton /* 124918217Slinton * Execute a func command. 125018217Slinton */ 125118217Slinton 125218217Slinton private func (p) 125318217Slinton Node p; 125418217Slinton { 125518217Slinton Symbol s, f; 125618217Slinton Address addr; 125718217Slinton 125818217Slinton if (p == nil) { 125918217Slinton printname(stdout, curfunc); 126018217Slinton putchar('\n'); 126118217Slinton } else { 126218217Slinton s = p->value.sym; 126318217Slinton if (isroutine(s)) { 126418217Slinton setcurfunc(s); 126516608Ssam } else { 126618217Slinton find(f, s->name) where isroutine(f) endfind(f); 126718217Slinton if (f == nil) { 126818217Slinton error("%s is not a procedure or function", symname(s)); 126916608Ssam } 127018217Slinton setcurfunc(f); 12719662Slinton } 127218217Slinton addr = codeloc(curfunc); 127318217Slinton if (addr != NOADDR) { 127418217Slinton setsource(srcfilename(addr)); 127518217Slinton cursrcline = srcline(addr); 127618217Slinton } 12779662Slinton } 12789662Slinton } 12799662Slinton 12809662Slinton /* 128118217Slinton * Send a message to the current support person. 12829662Slinton */ 12839662Slinton 12849662Slinton public gripe() 12859662Slinton { 12869662Slinton typedef Operation(); 12879662Slinton Operation *old; 128814445Slinton int pid, status; 128916608Ssam extern int versionNumber; 129016608Ssam char subject[100]; 12919662Slinton 129233315Sdonn # ifdef MAINTAINER 129333315Sdonn puts("Type control-D to end your message. Be sure to include"); 129433315Sdonn puts("your name and the name of the file you are debugging."); 129533315Sdonn putchar('\n'); 129633315Sdonn old = signal(SIGINT, SIG_DFL); 129733315Sdonn sprintf(subject, "dbx (version 3.%d) gripe", versionNumber); 129833315Sdonn pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil); 129933315Sdonn signal(SIGINT, SIG_IGN); 130033315Sdonn pwait(pid, &status); 130133315Sdonn signal(SIGINT, old); 130233315Sdonn if (status == 0) { 130333315Sdonn puts("Thank you."); 130433315Sdonn } else { 130533315Sdonn puts("\nMail not sent."); 130633315Sdonn } 130733315Sdonn # else 130833315Sdonn puts("Sorry, no dbx maintainer available to gripe to."); 130933315Sdonn puts("Try contacting your system manager."); 131033315Sdonn # endif 13119662Slinton } 13129662Slinton 13139662Slinton /* 13149662Slinton * Give the user some help. 13159662Slinton */ 13169662Slinton 13179662Slinton public help() 13189662Slinton { 13199662Slinton puts("run - begin execution of the program"); 132016608Ssam puts("print <exp> - print the value of the expression"); 132116608Ssam puts("where - print currently active procedures"); 132216608Ssam puts("stop at <line> - suspend execution at the line"); 132316608Ssam puts("stop in <proc> - suspend execution when <proc> is called"); 13249662Slinton puts("cont - continue execution"); 13259662Slinton puts("step - single step one line"); 13269662Slinton puts("next - step to next line (skip over calls)"); 13279662Slinton puts("trace <line#> - trace execution of the line"); 13289662Slinton puts("trace <proc> - trace calls to the procedure"); 13299662Slinton puts("trace <var> - trace changes to the variable"); 13309662Slinton puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 13319662Slinton puts("status - print trace/stop's in effect"); 13329662Slinton puts("delete <number> - remove trace or stop of given number"); 133316608Ssam puts("call <proc> - call a procedure in program"); 13349662Slinton puts("whatis <name> - print the declaration of the name"); 13359662Slinton puts("list <line>, <line> - list source lines"); 13369662Slinton puts("gripe - send mail to the person in charge of dbx"); 13379662Slinton puts("quit - exit dbx"); 13389662Slinton } 13399662Slinton 13409662Slinton /* 13419662Slinton * Divert output to the given file name. 13429662Slinton * Cannot redirect to an existing file. 13439662Slinton */ 13449662Slinton 13459662Slinton private int so_fd; 13469662Slinton private Boolean notstdout; 13479662Slinton 13489662Slinton public setout(filename) 13499662Slinton String filename; 13509662Slinton { 13519662Slinton File f; 13529662Slinton 13539662Slinton f = fopen(filename, "r"); 13549662Slinton if (f != nil) { 13559662Slinton fclose(f); 13569662Slinton error("%s: file already exists", filename); 13579662Slinton } else { 13589662Slinton so_fd = dup(1); 13599662Slinton close(1); 13609662Slinton if (creat(filename, 0666) == nil) { 13619662Slinton unsetout(); 13629662Slinton error("can't create %s", filename); 13639662Slinton } 13649662Slinton notstdout = true; 13659662Slinton } 13669662Slinton } 13679662Slinton 13689662Slinton /* 13699662Slinton * Revert output to standard output. 13709662Slinton */ 13719662Slinton 13729662Slinton public unsetout() 13739662Slinton { 13749662Slinton fflush(stdout); 13759662Slinton close(1); 13769662Slinton if (dup(so_fd) != 1) { 13779662Slinton panic("standard out dup failed"); 13789662Slinton } 13799662Slinton close(so_fd); 13809662Slinton notstdout = false; 13819662Slinton } 13829662Slinton 13839662Slinton /* 13849662Slinton * Determine is standard output is currently being redirected 13859662Slinton * to a file (as far as we know). 13869662Slinton */ 13879662Slinton 13889662Slinton public Boolean isredirected() 13899662Slinton { 13909662Slinton return notstdout; 13919662Slinton } 1392