19669Slinton /* Copyright (c) 1982 Regents of the University of California */ 29669Slinton 3*17530Sralph static char sccsid[] = "@(#)main.c 1.10 (Berkeley) 12/18/84"; 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" 1412483Slinton #include "symbols.h" 159669Slinton #include "scanner.h" 169669Slinton #include "process.h" 1716613Ssam #include "runtime.h" 189669Slinton #include "source.h" 199669Slinton #include "object.h" 2012483Slinton #include "mappings.h" 219669Slinton 229669Slinton #ifndef public 239669Slinton 249669Slinton #define isterm(file) (interactive or isatty(fileno(file))) 259669Slinton 2611868Slinton #include <sgtty.h> 27*17530Sralph #include <fcntl.h> 2811868Slinton 29*17530Sralph typedef struct { 30*17530Sralph struct sgttyb sg; /* standard sgttyb structure */ 31*17530Sralph struct tchars tc; /* terminal characters */ 32*17530Sralph struct ltchars ltc; /* local special characters */ 33*17530Sralph int ldisc; /* line discipline */ 34*17530Sralph int local; /* TIOCLGET */ 35*17530Sralph int fcflags; /* fcntl(2) F_GETFL, F_SETFL */ 36*17530Sralph } Ttyinfo; 3711868Slinton 389669Slinton #endif 399669Slinton 409669Slinton public Boolean coredump; /* true if using a core dump */ 419669Slinton public Boolean runfirst; /* run program immediately */ 429669Slinton public Boolean interactive; /* standard input IS a terminal */ 439669Slinton public Boolean lexdebug; /* trace yylex return values */ 449669Slinton public Boolean tracebpts; /* trace create/delete breakpoints */ 459669Slinton public Boolean traceexec; /* trace process execution */ 469669Slinton public Boolean tracesyms; /* print symbols as their read */ 4716613Ssam public Boolean traceblocks; /* trace blocks while reading symbols */ 489669Slinton 499669Slinton public File corefile; /* File id of core dump */ 509669Slinton 519669Slinton #define FIRST_TIME 0 /* initial value setjmp returns */ 529669Slinton 539669Slinton private Boolean initdone = false; /* true if initialization done */ 549669Slinton private jmp_buf env; /* setjmp/longjmp data */ 559669Slinton private char namebuf[512]; /* possible name of object file */ 569669Slinton private int firstarg; /* first program argument (for -r) */ 579669Slinton 5811868Slinton private Ttyinfo ttyinfo; 5911868Slinton 609669Slinton private catchintr(); 619669Slinton 629669Slinton /* 639669Slinton * Main program. 649669Slinton */ 659669Slinton 669669Slinton main(argc, argv) 679669Slinton int argc; 689669Slinton String argv[]; 699669Slinton { 7016613Ssam register integer i; 7111868Slinton extern String date; 7216613Ssam extern integer versionNumber; 739669Slinton 749669Slinton cmdname = argv[0]; 759669Slinton catcherrs(); 769669Slinton onsyserr(EINTR, nil); 7716925Ssam setlinebuf(stderr); 7816613Ssam printf("dbx version %d of %s.\nType 'help' for help.\n", 7916613Ssam versionNumber, date); 8011868Slinton fflush(stdout); 819669Slinton scanargs(argc, argv); 829669Slinton language_init(); 839669Slinton process_init(); 849669Slinton if (runfirst) { 859669Slinton if (setjmp(env) == FIRST_TIME) { 869669Slinton arginit(); 879669Slinton for (i = firstarg; i < argc; i++) { 889669Slinton newarg(argv[i]); 899669Slinton } 909669Slinton run(); 919669Slinton /* NOTREACHED */ 929669Slinton } else { 939669Slinton runfirst = false; 949669Slinton } 959669Slinton } else { 969669Slinton init(); 979669Slinton } 9816613Ssam if (setjmp(env) != FIRST_TIME) { 9916613Ssam restoretty(stdout, &ttyinfo); 10016613Ssam } 1019669Slinton signal(SIGINT, catchintr); 10216925Ssam if (isterm(stdin)) { 10316925Ssam printf("(%s) ", cmdname); 10416925Ssam fflush(stdout); 10516925Ssam } 10616925Ssam endshellmode(); /* after an error longjmp */ 10716925Ssam startaliasing(); 1089669Slinton yyparse(); 1099669Slinton putchar('\n'); 1109669Slinton quit(0); 1119669Slinton } 1129669Slinton 1139669Slinton /* 1149669Slinton * Initialize the world, including setting initial input file 1159669Slinton * if the file exists. 1169669Slinton */ 1179669Slinton 1189669Slinton public init() 1199669Slinton { 1209669Slinton File f; 1219669Slinton String home; 1229669Slinton char buf[100]; 1239669Slinton extern String getenv(); 1249669Slinton 12511868Slinton savetty(stdout, &ttyinfo); 1269669Slinton enterkeywords(); 1279669Slinton scanner_init(); 1289669Slinton if (not coredump and not runfirst) { 1299669Slinton start(nil, nil, nil); 1309669Slinton } 13111868Slinton printf("reading symbolic information ..."); 13211868Slinton fflush(stdout); 1339669Slinton readobj(objname); 13411868Slinton printf("\n"); 13511868Slinton fflush(stdout); 13612483Slinton if (coredump) { 13716613Ssam setcurfunc(whatblock(pc)); 13812483Slinton } else { 13916613Ssam setcurfunc(program); 14012483Slinton } 1419669Slinton bpinit(); 1429669Slinton f = fopen(initfile, "r"); 1439669Slinton if (f != nil) { 1449669Slinton fclose(f); 1459669Slinton setinput(initfile); 1469669Slinton } else { 1479669Slinton home = getenv("HOME"); 1489669Slinton if (home != nil) { 1499669Slinton sprintf(buf, "%s/%s", home, initfile); 1509669Slinton f = fopen(buf, "r"); 1519669Slinton if (f != nil) { 1529669Slinton fclose(f); 1539669Slinton setinput(strdup(buf)); 1549669Slinton } 1559669Slinton } 1569669Slinton } 1579669Slinton initdone = true; 1589669Slinton } 1599669Slinton 1609669Slinton /* 1619669Slinton * Re-initialize the world, first de-allocating all storage. 1629669Slinton * This is necessary when the symbol information must be re-read 1639669Slinton * from the object file when it has changed. 1649669Slinton * 1659669Slinton * Before "forgetting" things, we save the current tracing/breakpoint 1669669Slinton * information to a temp file. Then after re-creating the world, 1679669Slinton * we read the temp file as commands. This isn't always the right thing; 1689669Slinton * if a procedure that was being traced is deleted, an error message 1699669Slinton * will be generated. 1709669Slinton * 1719669Slinton * If the argument vector is not nil, then this is re-initialize is being 1729669Slinton * done in preparation for running the program. Since we want to process 1739669Slinton * the commands in the temp file before running the program, we add the 1749669Slinton * run command at the end of the temp file. In this case, reinit longjmps 1759669Slinton * back to parsing rather than returning. 1769669Slinton */ 1779669Slinton 1789669Slinton public reinit(argv, infile, outfile) 1799669Slinton String *argv; 1809669Slinton String infile; 1819669Slinton String outfile; 1829669Slinton { 1839669Slinton register Integer i; 1849669Slinton String tmpfile; 1859669Slinton extern String mktemp(); 1869669Slinton 1879669Slinton tmpfile = mktemp("/tmp/dbxXXXX"); 1889669Slinton setout(tmpfile); 1899669Slinton status(); 1909669Slinton print_alias(nil); 1919669Slinton if (argv != nil) { 1929669Slinton printf("run"); 1939669Slinton for (i = 1; argv[i] != nil; i++) { 1949669Slinton printf(" %s", argv[i]); 1959669Slinton } 1969669Slinton if (infile != nil) { 1979669Slinton printf(" < %s", infile); 1989669Slinton } 1999669Slinton if (outfile != nil) { 2009669Slinton printf(" > %s", outfile); 2019669Slinton } 2029669Slinton putchar('\n'); 2039669Slinton } 2049669Slinton unsetout(); 2059669Slinton bpfree(); 2069669Slinton objfree(); 2079669Slinton process_init(); 2089669Slinton enterkeywords(); 2099669Slinton scanner_init(); 2109669Slinton readobj(objname); 2119669Slinton bpinit(); 2129669Slinton fflush(stdout); 2139669Slinton setinput(tmpfile); 2149669Slinton unlink(tmpfile); 2159669Slinton if (argv != nil) { 2169669Slinton longjmp(env, 1); 2179669Slinton /* NOTREACHED */ 2189669Slinton } 2199669Slinton } 2209669Slinton 2219669Slinton /* 2229669Slinton * After a non-fatal error we jump back to command parsing. 2239669Slinton */ 2249669Slinton 2259669Slinton public erecover() 2269669Slinton { 2279669Slinton if (initdone) { 2289669Slinton gobble(); 2299669Slinton longjmp(env, 1); 2309669Slinton } 2319669Slinton } 2329669Slinton 2339669Slinton /* 2349669Slinton * This routine is called when an interrupt occurs. 2359669Slinton */ 2369669Slinton 2379669Slinton private catchintr() 2389669Slinton { 2399669Slinton putchar('\n'); 2409669Slinton longjmp(env, 1); 2419669Slinton } 2429669Slinton 2439669Slinton /* 2449669Slinton * Scan the argument list. 2459669Slinton */ 2469669Slinton 2479669Slinton private scanargs(argc, argv) 2489669Slinton int argc; 2499669Slinton String argv[]; 2509669Slinton { 2519669Slinton register int i, j; 2529669Slinton register Boolean foundfile; 2539669Slinton register File f; 2549669Slinton char *tmp; 2559669Slinton 2569669Slinton runfirst = false; 2579669Slinton interactive = false; 2589669Slinton lexdebug = false; 2599669Slinton tracebpts = false; 2609669Slinton traceexec = false; 2619669Slinton tracesyms = false; 26216613Ssam traceblocks = false; 2639669Slinton foundfile = false; 2649669Slinton corefile = nil; 2659669Slinton coredump = true; 2669669Slinton sourcepath = list_alloc(); 2679669Slinton list_append(list_item("."), nil, sourcepath); 2689669Slinton i = 1; 26916613Ssam while (i < argc and (not foundfile or corefile == nil)) { 2709669Slinton if (argv[i][0] == '-') { 2719669Slinton if (streq(argv[i], "-I")) { 2729669Slinton ++i; 2739669Slinton if (i >= argc) { 2749669Slinton fatal("missing directory for -I"); 2759669Slinton } 2769669Slinton list_append(list_item(argv[i]), nil, sourcepath); 2779669Slinton } else { 2789669Slinton for (j = 1; argv[i][j] != '\0'; j++) { 2799669Slinton setoption(argv[i][j]); 2809669Slinton } 2819669Slinton } 2829669Slinton } else if (not foundfile) { 2839669Slinton objname = argv[i]; 2849669Slinton foundfile = true; 2859669Slinton } else if (coredump and corefile == nil) { 2869669Slinton corefile = fopen(argv[i], "r"); 2879669Slinton if (corefile == nil) { 2889669Slinton coredump = false; 2899669Slinton } 2909669Slinton } 2919669Slinton ++i; 2929669Slinton } 2939669Slinton if (i < argc and not runfirst) { 2949669Slinton fatal("extraneous argument %s", argv[i]); 2959669Slinton } 2969669Slinton firstarg = i; 2979669Slinton if (not foundfile and isatty(0)) { 2989669Slinton printf("enter object file name (default is `%s'): ", objname); 2999669Slinton fflush(stdout); 3009669Slinton gets(namebuf); 3019669Slinton if (namebuf[0] != '\0') { 3029669Slinton objname = namebuf; 3039669Slinton } 3049669Slinton } 3059669Slinton f = fopen(objname, "r"); 3069669Slinton if (f == nil) { 3079669Slinton fatal("can't read %s", objname); 3089669Slinton } else { 3099669Slinton fclose(f); 3109669Slinton } 3119669Slinton if (rindex(objname, '/') != nil) { 3129669Slinton tmp = strdup(objname); 3139669Slinton *(rindex(tmp, '/')) = '\0'; 3149669Slinton list_append(list_item(tmp), nil, sourcepath); 3159669Slinton } 3169669Slinton if (coredump and corefile == nil) { 3179669Slinton corefile = fopen("core", "r"); 3189669Slinton if (corefile == nil) { 3199669Slinton coredump = false; 3209669Slinton } 3219669Slinton } 3229669Slinton } 3239669Slinton 3249669Slinton /* 3259669Slinton * Take appropriate action for recognized command argument. 3269669Slinton */ 3279669Slinton 3289669Slinton private setoption(c) 3299669Slinton char c; 3309669Slinton { 3319669Slinton switch (c) { 3329669Slinton case 'r': /* run program before accepting commands */ 3339669Slinton runfirst = true; 3349669Slinton coredump = false; 3359669Slinton break; 3369669Slinton 3379669Slinton case 'i': 3389669Slinton interactive = true; 3399669Slinton break; 3409669Slinton 3419669Slinton case 'b': 3429669Slinton tracebpts = true; 3439669Slinton break; 3449669Slinton 3459669Slinton case 'e': 3469669Slinton traceexec = true; 3479669Slinton break; 3489669Slinton 3499669Slinton case 's': 3509669Slinton tracesyms = true; 3519669Slinton break; 3529669Slinton 35316613Ssam case 'n': 35416613Ssam traceblocks = true; 35516613Ssam break; 35616613Ssam 3579669Slinton case 'l': 3589669Slinton lexdebug = true; 3599669Slinton break; 3609669Slinton 3619669Slinton default: 3629669Slinton fatal("unknown option '%c'", c); 3639669Slinton } 3649669Slinton } 3659669Slinton 3669669Slinton /* 36711868Slinton * Save/restore the state of a tty. 36811868Slinton */ 36911868Slinton 37011868Slinton public savetty(f, t) 37111868Slinton File f; 37211868Slinton Ttyinfo *t; 37311868Slinton { 374*17530Sralph ioctl(fileno(f), TIOCGETP, &(t->sg)); 375*17530Sralph ioctl(fileno(f), TIOCGETC, &(t->tc)); 376*17530Sralph ioctl(fileno(f), TIOCGLTC, &(t->ltc)); 377*17530Sralph ioctl(fileno(f), TIOCGETD, &(t->ldisc)); 378*17530Sralph ioctl(fileno(f), TIOCLGET, &(t->local)); 379*17530Sralph t->fcflags = fcntl(fileno(f), F_GETFL, 0); 38011868Slinton } 38111868Slinton 38211868Slinton public restoretty(f, t) 38311868Slinton File f; 38411868Slinton Ttyinfo *t; 38511868Slinton { 386*17530Sralph ioctl(fileno(f), TIOCSETN, &(t->sg)); 387*17530Sralph ioctl(fileno(f), TIOCSETC, &(t->tc)); 388*17530Sralph ioctl(fileno(f), TIOCSLTC, &(t->ltc)); 389*17530Sralph ioctl(fileno(f), TIOCSETD, &(t->ldisc)); 390*17530Sralph ioctl(fileno(f), TIOCLSET, &(t->local)); 391*17530Sralph (void) fcntl(fileno(f), F_SETFL, t->fcflags); 39211868Slinton } 39311868Slinton 39411868Slinton /* 3959669Slinton * Exit gracefully. 3969669Slinton */ 3979669Slinton 3989669Slinton public quit(r) 3999669Slinton Integer r; 4009669Slinton { 40116613Ssam pterm(process); 4029669Slinton exit(r); 4039669Slinton } 404