19669Slinton /* Copyright (c) 1982 Regents of the University of California */ 29669Slinton 3*10607Slinton static char sccsid[] = "@(#)main.c 1.3 01/23/83"; 49669Slinton 59669Slinton /* 69669Slinton * Debugger main routine. 79669Slinton */ 89669Slinton 99669Slinton #include "defs.h" 109669Slinton #include <setjmp.h> 119669Slinton #include <signal.h> 129669Slinton #include <errno.h> 139669Slinton #include "main.h" 149669Slinton #include "scanner.h" 159669Slinton #include "process.h" 169669Slinton #include "source.h" 179669Slinton #include "object.h" 189669Slinton 199669Slinton #ifndef public 209669Slinton 219669Slinton #define isterm(file) (interactive or isatty(fileno(file))) 229669Slinton 239669Slinton #endif 249669Slinton 259669Slinton public Boolean coredump; /* true if using a core dump */ 269669Slinton public Boolean runfirst; /* run program immediately */ 279669Slinton public Boolean interactive; /* standard input IS a terminal */ 289669Slinton public Boolean lexdebug; /* trace yylex return values */ 299669Slinton public Boolean tracebpts; /* trace create/delete breakpoints */ 309669Slinton public Boolean traceexec; /* trace process execution */ 319669Slinton public Boolean tracesyms; /* print symbols as their read */ 329669Slinton 339669Slinton public File corefile; /* File id of core dump */ 349669Slinton 359669Slinton #define FIRST_TIME 0 /* initial value setjmp returns */ 369669Slinton 379669Slinton private Boolean initdone = false; /* true if initialization done */ 389669Slinton private jmp_buf env; /* setjmp/longjmp data */ 399669Slinton private char outbuf[BUFSIZ]; /* standard output buffer */ 409669Slinton private char namebuf[512]; /* possible name of object file */ 419669Slinton private int firstarg; /* first program argument (for -r) */ 429669Slinton 439669Slinton private catchintr(); 449669Slinton 459669Slinton /* 469669Slinton * Main program. 479669Slinton */ 489669Slinton 499669Slinton main(argc, argv) 509669Slinton int argc; 519669Slinton String argv[]; 529669Slinton { 539669Slinton register Integer i; 549669Slinton 559669Slinton cmdname = argv[0]; 569669Slinton catcherrs(); 579669Slinton onsyserr(EINTR, nil); 589669Slinton setbuf(stdout, outbuf); 599669Slinton scanargs(argc, argv); 609669Slinton language_init(); 619669Slinton process_init(); 629669Slinton if (runfirst) { 639669Slinton if (setjmp(env) == FIRST_TIME) { 649669Slinton arginit(); 659669Slinton for (i = firstarg; i < argc; i++) { 669669Slinton newarg(argv[i]); 679669Slinton } 689669Slinton run(); 699669Slinton /* NOTREACHED */ 709669Slinton } else { 719669Slinton runfirst = false; 729669Slinton } 739669Slinton } else { 749669Slinton init(); 759669Slinton } 769669Slinton setjmp(env); 779669Slinton signal(SIGINT, catchintr); 789669Slinton yyparse(); 799669Slinton putchar('\n'); 809669Slinton quit(0); 819669Slinton } 829669Slinton 839669Slinton /* 849669Slinton * Initialize the world, including setting initial input file 859669Slinton * if the file exists. 869669Slinton */ 879669Slinton 889669Slinton public init() 899669Slinton { 909669Slinton File f; 919669Slinton String home; 929669Slinton char buf[100]; 939669Slinton extern String getenv(); 949669Slinton 959669Slinton enterkeywords(); 969669Slinton scanner_init(); 979669Slinton if (not coredump and not runfirst) { 989669Slinton start(nil, nil, nil); 999669Slinton } 1009669Slinton readobj(objname); 1019669Slinton curfunc = program; 1029669Slinton bpinit(); 1039669Slinton f = fopen(initfile, "r"); 1049669Slinton if (f != nil) { 1059669Slinton fclose(f); 1069669Slinton setinput(initfile); 1079669Slinton } else { 1089669Slinton home = getenv("HOME"); 1099669Slinton if (home != nil) { 1109669Slinton sprintf(buf, "%s/%s", home, initfile); 1119669Slinton f = fopen(buf, "r"); 1129669Slinton if (f != nil) { 1139669Slinton fclose(f); 1149669Slinton setinput(strdup(buf)); 1159669Slinton } 1169669Slinton } 1179669Slinton } 1189669Slinton initdone = true; 1199669Slinton } 1209669Slinton 1219669Slinton /* 1229669Slinton * Re-initialize the world, first de-allocating all storage. 1239669Slinton * This is necessary when the symbol information must be re-read 1249669Slinton * from the object file when it has changed. 1259669Slinton * 1269669Slinton * Before "forgetting" things, we save the current tracing/breakpoint 1279669Slinton * information to a temp file. Then after re-creating the world, 1289669Slinton * we read the temp file as commands. This isn't always the right thing; 1299669Slinton * if a procedure that was being traced is deleted, an error message 1309669Slinton * will be generated. 1319669Slinton * 1329669Slinton * If the argument vector is not nil, then this is re-initialize is being 1339669Slinton * done in preparation for running the program. Since we want to process 1349669Slinton * the commands in the temp file before running the program, we add the 1359669Slinton * run command at the end of the temp file. In this case, reinit longjmps 1369669Slinton * back to parsing rather than returning. 1379669Slinton */ 1389669Slinton 1399669Slinton public reinit(argv, infile, outfile) 1409669Slinton String *argv; 1419669Slinton String infile; 1429669Slinton String outfile; 1439669Slinton { 1449669Slinton register Integer i; 1459669Slinton String tmpfile; 1469669Slinton extern String mktemp(); 1479669Slinton 1489669Slinton tmpfile = mktemp("/tmp/dbxXXXX"); 1499669Slinton setout(tmpfile); 1509669Slinton status(); 1519669Slinton print_alias(nil); 1529669Slinton if (argv != nil) { 1539669Slinton printf("run"); 1549669Slinton for (i = 1; argv[i] != nil; i++) { 1559669Slinton printf(" %s", argv[i]); 1569669Slinton } 1579669Slinton if (infile != nil) { 1589669Slinton printf(" < %s", infile); 1599669Slinton } 1609669Slinton if (outfile != nil) { 1619669Slinton printf(" > %s", outfile); 1629669Slinton } 1639669Slinton putchar('\n'); 1649669Slinton } 1659669Slinton unsetout(); 1669669Slinton bpfree(); 1679669Slinton objfree(); 1689669Slinton process_init(); 1699669Slinton enterkeywords(); 1709669Slinton scanner_init(); 1719669Slinton readobj(objname); 1729669Slinton bpinit(); 1739669Slinton fflush(stdout); 1749669Slinton setinput(tmpfile); 1759669Slinton unlink(tmpfile); 1769669Slinton if (argv != nil) { 1779669Slinton longjmp(env, 1); 1789669Slinton /* NOTREACHED */ 1799669Slinton } 1809669Slinton } 1819669Slinton 1829669Slinton /* 1839669Slinton * After a non-fatal error we jump back to command parsing. 1849669Slinton */ 1859669Slinton 1869669Slinton public erecover() 1879669Slinton { 1889669Slinton if (initdone) { 1899669Slinton gobble(); 1909669Slinton longjmp(env, 1); 1919669Slinton } 1929669Slinton } 1939669Slinton 1949669Slinton /* 1959669Slinton * This routine is called when an interrupt occurs. 1969669Slinton */ 1979669Slinton 1989669Slinton private catchintr() 1999669Slinton { 2009669Slinton putchar('\n'); 2019669Slinton longjmp(env, 1); 2029669Slinton } 2039669Slinton 2049669Slinton /* 2059669Slinton * Scan the argument list. 2069669Slinton */ 2079669Slinton 2089669Slinton private scanargs(argc, argv) 2099669Slinton int argc; 2109669Slinton String argv[]; 2119669Slinton { 2129669Slinton register int i, j; 2139669Slinton register Boolean foundfile; 2149669Slinton register File f; 2159669Slinton char *tmp; 2169669Slinton 2179669Slinton runfirst = false; 2189669Slinton interactive = false; 2199669Slinton lexdebug = false; 2209669Slinton tracebpts = false; 2219669Slinton traceexec = false; 2229669Slinton tracesyms = false; 2239669Slinton foundfile = false; 2249669Slinton corefile = nil; 2259669Slinton coredump = true; 2269669Slinton sourcepath = list_alloc(); 2279669Slinton list_append(list_item("."), nil, sourcepath); 2289669Slinton i = 1; 229*10607Slinton while (i < argc and (not foundfile or corefile == nil)) { 2309669Slinton if (argv[i][0] == '-') { 2319669Slinton if (streq(argv[i], "-I")) { 2329669Slinton ++i; 2339669Slinton if (i >= argc) { 2349669Slinton fatal("missing directory for -I"); 2359669Slinton } 2369669Slinton list_append(list_item(argv[i]), nil, sourcepath); 2379669Slinton } else { 2389669Slinton for (j = 1; argv[i][j] != '\0'; j++) { 2399669Slinton setoption(argv[i][j]); 2409669Slinton } 2419669Slinton } 2429669Slinton } else if (not foundfile) { 2439669Slinton objname = argv[i]; 2449669Slinton foundfile = true; 2459669Slinton } else if (coredump and corefile == nil) { 2469669Slinton corefile = fopen(argv[i], "r"); 2479669Slinton if (corefile == nil) { 2489669Slinton coredump = false; 2499669Slinton } 2509669Slinton } 2519669Slinton ++i; 2529669Slinton } 2539669Slinton if (i < argc and not runfirst) { 2549669Slinton fatal("extraneous argument %s", argv[i]); 2559669Slinton } 2569669Slinton firstarg = i; 2579669Slinton if (not foundfile and isatty(0)) { 2589669Slinton printf("enter object file name (default is `%s'): ", objname); 2599669Slinton fflush(stdout); 2609669Slinton gets(namebuf); 2619669Slinton if (namebuf[0] != '\0') { 2629669Slinton objname = namebuf; 2639669Slinton } 2649669Slinton } 2659669Slinton f = fopen(objname, "r"); 2669669Slinton if (f == nil) { 2679669Slinton fatal("can't read %s", objname); 2689669Slinton } else { 2699669Slinton fclose(f); 2709669Slinton } 2719669Slinton if (rindex(objname, '/') != nil) { 2729669Slinton tmp = strdup(objname); 2739669Slinton *(rindex(tmp, '/')) = '\0'; 2749669Slinton list_append(list_item(tmp), nil, sourcepath); 2759669Slinton } 2769669Slinton if (coredump and corefile == nil) { 2779669Slinton corefile = fopen("core", "r"); 2789669Slinton if (corefile == nil) { 2799669Slinton coredump = false; 2809669Slinton } 2819669Slinton } 2829669Slinton } 2839669Slinton 2849669Slinton /* 2859669Slinton * Take appropriate action for recognized command argument. 2869669Slinton */ 2879669Slinton 2889669Slinton private setoption(c) 2899669Slinton char c; 2909669Slinton { 2919669Slinton switch (c) { 2929669Slinton case 'r': /* run program before accepting commands */ 2939669Slinton runfirst = true; 2949669Slinton coredump = false; 2959669Slinton break; 2969669Slinton 2979669Slinton case 'i': 2989669Slinton interactive = true; 2999669Slinton break; 3009669Slinton 3019669Slinton case 'b': 3029669Slinton tracebpts = true; 3039669Slinton break; 3049669Slinton 3059669Slinton case 'e': 3069669Slinton traceexec = true; 3079669Slinton break; 3089669Slinton 3099669Slinton case 's': 3109669Slinton tracesyms = true; 3119669Slinton break; 3129669Slinton 3139669Slinton case 'l': 3149669Slinton # ifdef LEXDEBUG 3159669Slinton lexdebug = true; 3169669Slinton # else 3179669Slinton fatal("\"-l\" only applicable when compiled with LEXDEBUG"); 3189669Slinton # endif 3199669Slinton break; 3209669Slinton 3219669Slinton default: 3229669Slinton fatal("unknown option '%c'", c); 3239669Slinton } 3249669Slinton } 3259669Slinton 3269669Slinton /* 3279669Slinton * Exit gracefully. 3289669Slinton */ 3299669Slinton 3309669Slinton public quit(r) 3319669Slinton Integer r; 3329669Slinton { 3339669Slinton exit(r); 3349669Slinton } 335