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