121609Sdist /* 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. 1621609Sdist */ 179669Slinton 1821609Sdist #ifndef lint 1921609Sdist char copyright[] = 20*38105Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2121609Sdist All rights reserved.\n"; 22*38105Sbostic #endif /* not lint */ 239669Slinton 2421609Sdist #ifndef lint 25*38105Sbostic static char sccsid[] = "@(#)main.c 5.6 (Berkeley) 05/23/89"; 26*38105Sbostic #endif /* not lint */ 2721609Sdist 289669Slinton /* 299669Slinton * Debugger main routine. 309669Slinton */ 319669Slinton 329669Slinton #include "defs.h" 339669Slinton #include <setjmp.h> 349669Slinton #include <signal.h> 359669Slinton #include <errno.h> 369669Slinton #include "main.h" 3733322Sdonn #include "tree.h" 3818223Slinton #include "eval.h" 3918223Slinton #include "debug.h" 4012483Slinton #include "symbols.h" 419669Slinton #include "scanner.h" 4218223Slinton #include "keywords.h" 439669Slinton #include "process.h" 4416613Ssam #include "runtime.h" 459669Slinton #include "source.h" 469669Slinton #include "object.h" 4712483Slinton #include "mappings.h" 4818223Slinton #include "coredump.h" 4937790Sbostic #include "pathnames.h" 509669Slinton 519669Slinton #ifndef public 529669Slinton 539669Slinton #define isterm(file) (interactive or isatty(fileno(file))) 549669Slinton 5533322Sdonn #ifdef IRIS 5633322Sdonn # include <termio.h> 5711868Slinton 5833322Sdonn typedef struct termio Ttyinfo; 5933322Sdonn #else 6033322Sdonn # include <sgtty.h> 6133322Sdonn # include <fcntl.h> 6211868Slinton 6333322Sdonn typedef struct { 6433322Sdonn struct sgttyb sg; /* standard sgttyb structure */ 6533322Sdonn struct tchars tc; /* terminal characters */ 6633322Sdonn struct ltchars ltc; /* local special characters */ 6733322Sdonn integer ldisc; /* line discipline */ 6833322Sdonn integer local; /* TIOCLGET */ 6933322Sdonn integer fcflags; /* fcntl(2) F_GETFL, F_SETFL */ 7033322Sdonn } Ttyinfo; 719669Slinton #endif 729669Slinton 7333322Sdonn #endif 7433322Sdonn 7518223Slinton public boolean coredump; /* true if using a core dump */ 7618223Slinton public boolean runfirst; /* run program immediately */ 7718223Slinton public boolean interactive; /* standard input IS a terminal */ 7818223Slinton public boolean lexdebug; /* trace scanner return values */ 7918223Slinton public boolean tracebpts; /* trace create/delete breakpoints */ 8018223Slinton public boolean traceexec; /* trace execution */ 8118223Slinton public boolean tracesyms; /* print symbols are they are read */ 8218223Slinton public boolean traceblocks; /* trace blocks while reading symbols */ 8318223Slinton public boolean vaddrs; /* map addresses through page tables */ 8433322Sdonn public boolean quiet; /* don't print heading */ 8533322Sdonn public boolean autostrip; /* strip C++ prefixes */ 869669Slinton 879669Slinton public File corefile; /* File id of core dump */ 889669Slinton 8933322Sdonn public integer versionNumber = 4; 9033322Sdonn 919669Slinton #define FIRST_TIME 0 /* initial value setjmp returns */ 929669Slinton 939669Slinton private Boolean initdone = false; /* true if initialization done */ 949669Slinton private jmp_buf env; /* setjmp/longjmp data */ 9518223Slinton private char outbuf[BUFSIZ]; /* standard output buffer */ 969669Slinton private char namebuf[512]; /* possible name of object file */ 979669Slinton 9811868Slinton private Ttyinfo ttyinfo; 9918223Slinton private String corename; /* name of core file */ 10011868Slinton 1019669Slinton private catchintr(); 10233322Sdonn private char **scanargs(); 1039669Slinton 1049669Slinton /* 1059669Slinton * Main program. 1069669Slinton */ 1079669Slinton 1089669Slinton main(argc, argv) 1099669Slinton int argc; 1109669Slinton String argv[]; 1119669Slinton { 11216613Ssam extern integer versionNumber; 11331002Sbostic char **scanargs(); 1149669Slinton 11531002Sbostic if (!(cmdname = rindex(*argv, '/'))) 11631002Sbostic cmdname = *argv; 11731002Sbostic else 11831002Sbostic ++cmdname; 11931002Sbostic 1209669Slinton catcherrs(); 1219669Slinton onsyserr(EINTR, nil); 12233322Sdonn onsyserr(EADDRINUSE, nil); 12333322Sdonn onsyserr(ENXIO, nil); 12418223Slinton setbuf(stdout, outbuf); 12531002Sbostic argv = scanargs(argc, argv); 12633322Sdonn if (not runfirst and not quiet) { 12733322Sdonn printheading(); 12833322Sdonn } 12933322Sdonn openfiles(); 1309669Slinton language_init(); 13118223Slinton symbols_init(); 1329669Slinton process_init(); 13326328Ssam optab_init(); 1349669Slinton if (runfirst) { 1359669Slinton if (setjmp(env) == FIRST_TIME) { 1369669Slinton arginit(); 13731002Sbostic while (*argv) 13831002Sbostic newarg(*argv++); 1399669Slinton run(); 1409669Slinton /* NOTREACHED */ 1419669Slinton } else { 1429669Slinton runfirst = false; 1439669Slinton } 1449669Slinton } else { 1459669Slinton init(); 1469669Slinton } 14716613Ssam if (setjmp(env) != FIRST_TIME) { 14816613Ssam restoretty(stdout, &ttyinfo); 14916613Ssam } 1509669Slinton signal(SIGINT, catchintr); 1519669Slinton yyparse(); 1529669Slinton putchar('\n'); 1539669Slinton quit(0); 1549669Slinton } 1559669Slinton 15633322Sdonn public printheading () 15733322Sdonn { 15833322Sdonn extern String date; 15933322Sdonn 16033322Sdonn printf("dbx version 3.%d of %s.\nType 'help' for help.\n", 16133322Sdonn versionNumber, date 16233322Sdonn ); 16333322Sdonn fflush(stdout); 16433322Sdonn } 16533322Sdonn 1669669Slinton /* 1679669Slinton * Initialize the world, including setting initial input file 1689669Slinton * if the file exists. 1699669Slinton */ 1709669Slinton 1719669Slinton public init() 1729669Slinton { 1739669Slinton File f; 1749669Slinton String home; 1759669Slinton char buf[100]; 1769669Slinton extern String getenv(); 1779669Slinton 17811868Slinton savetty(stdout, &ttyinfo); 1799669Slinton enterkeywords(); 1809669Slinton scanner_init(); 1819669Slinton if (not coredump and not runfirst) { 1829669Slinton start(nil, nil, nil); 1839669Slinton } 18411868Slinton printf("reading symbolic information ..."); 18511868Slinton fflush(stdout); 1869669Slinton readobj(objname); 18711868Slinton printf("\n"); 18811868Slinton fflush(stdout); 18912483Slinton if (coredump) { 19018223Slinton printf("[using memory image in %s]\n", corename); 19118223Slinton if (vaddrs) { 19218223Slinton coredump_getkerinfo(); 19318223Slinton } 19433322Sdonn getsrcpos(); 19516613Ssam setcurfunc(whatblock(pc)); 19612483Slinton } else { 19716613Ssam setcurfunc(program); 19812483Slinton } 1999669Slinton bpinit(); 2009669Slinton f = fopen(initfile, "r"); 2019669Slinton if (f != nil) { 2029669Slinton fclose(f); 2039669Slinton setinput(initfile); 2049669Slinton } else { 2059669Slinton home = getenv("HOME"); 2069669Slinton if (home != nil) { 2079669Slinton sprintf(buf, "%s/%s", home, initfile); 2089669Slinton f = fopen(buf, "r"); 2099669Slinton if (f != nil) { 2109669Slinton fclose(f); 2119669Slinton setinput(strdup(buf)); 2129669Slinton } 2139669Slinton } 2149669Slinton } 2159669Slinton initdone = true; 2169669Slinton } 2179669Slinton 2189669Slinton /* 2199669Slinton * Re-initialize the world, first de-allocating all storage. 2209669Slinton * This is necessary when the symbol information must be re-read 2219669Slinton * from the object file when it has changed. 2229669Slinton * 2239669Slinton * Before "forgetting" things, we save the current tracing/breakpoint 2249669Slinton * information to a temp file. Then after re-creating the world, 2259669Slinton * we read the temp file as commands. This isn't always the right thing; 2269669Slinton * if a procedure that was being traced is deleted, an error message 2279669Slinton * will be generated. 2289669Slinton * 2299669Slinton * If the argument vector is not nil, then this is re-initialize is being 2309669Slinton * done in preparation for running the program. Since we want to process 2319669Slinton * the commands in the temp file before running the program, we add the 2329669Slinton * run command at the end of the temp file. In this case, reinit longjmps 2339669Slinton * back to parsing rather than returning. 2349669Slinton */ 2359669Slinton 2369669Slinton public reinit(argv, infile, outfile) 2379669Slinton String *argv; 2389669Slinton String infile; 2399669Slinton String outfile; 2409669Slinton { 2419669Slinton register Integer i; 2429669Slinton String tmpfile; 2439669Slinton extern String mktemp(); 2449669Slinton 24537790Sbostic tmpfile = mktemp(_PATH_TMP); 2469669Slinton setout(tmpfile); 2479669Slinton status(); 24818223Slinton alias(nil, nil, nil); 2499669Slinton if (argv != nil) { 2509669Slinton printf("run"); 2519669Slinton for (i = 1; argv[i] != nil; i++) { 2529669Slinton printf(" %s", argv[i]); 2539669Slinton } 2549669Slinton if (infile != nil) { 2559669Slinton printf(" < %s", infile); 2569669Slinton } 2579669Slinton if (outfile != nil) { 2589669Slinton printf(" > %s", outfile); 2599669Slinton } 2609669Slinton putchar('\n'); 2619669Slinton } 2629669Slinton unsetout(); 2639669Slinton bpfree(); 2649669Slinton objfree(); 26518223Slinton symbols_init(); 2669669Slinton process_init(); 2679669Slinton enterkeywords(); 2689669Slinton scanner_init(); 2699669Slinton readobj(objname); 2709669Slinton bpinit(); 2719669Slinton fflush(stdout); 2729669Slinton setinput(tmpfile); 2739669Slinton unlink(tmpfile); 2749669Slinton if (argv != nil) { 2759669Slinton longjmp(env, 1); 2769669Slinton /* NOTREACHED */ 2779669Slinton } 2789669Slinton } 2799669Slinton 2809669Slinton /* 28118223Slinton * After a non-fatal error we skip the rest of the current input line, and 28218223Slinton * jump back to command parsing. 2839669Slinton */ 2849669Slinton 2859669Slinton public erecover() 2869669Slinton { 2879669Slinton if (initdone) { 2889669Slinton gobble(); 2899669Slinton longjmp(env, 1); 2909669Slinton } 2919669Slinton } 2929669Slinton 2939669Slinton /* 2949669Slinton * This routine is called when an interrupt occurs. 2959669Slinton */ 2969669Slinton 2979669Slinton private catchintr() 2989669Slinton { 29918223Slinton if (isredirected()) { 30018223Slinton fflush(stdout); 30118223Slinton unsetout(); 30218223Slinton } 3039669Slinton putchar('\n'); 3049669Slinton longjmp(env, 1); 3059669Slinton } 3069669Slinton 3079669Slinton /* 3089669Slinton * Scan the argument list. 3099669Slinton */ 3109669Slinton 31133322Sdonn private char **scanargs (argc, argv) 3129669Slinton int argc; 3139669Slinton String argv[]; 3149669Slinton { 31531002Sbostic extern char *optarg; 31633322Sdonn extern integer optind; 31733322Sdonn integer ch; 3189669Slinton 3199669Slinton runfirst = false; 3209669Slinton interactive = false; 3219669Slinton lexdebug = false; 3229669Slinton tracebpts = false; 3239669Slinton traceexec = false; 3249669Slinton tracesyms = false; 32516613Ssam traceblocks = false; 32618223Slinton vaddrs = false; 32733322Sdonn quiet = false; 32833322Sdonn autostrip = true; 3299669Slinton corefile = nil; 3309669Slinton coredump = true; 3319669Slinton sourcepath = list_alloc(); 3329669Slinton list_append(list_item("."), nil, sourcepath); 33331002Sbostic 33433322Sdonn while ((ch = getopt(argc, argv, "I:abc:eiklnqrs")) != EOF) 33531002Sbostic switch((char)ch) { 33631002Sbostic case 'I': 33731002Sbostic list_append(list_item(optarg), nil, sourcepath); 33831002Sbostic break; 33933322Sdonn case 'a': 34033322Sdonn autostrip = false; 34133322Sdonn break; 34231002Sbostic case 'b': 34331002Sbostic tracebpts = true; 34431002Sbostic break; 34531002Sbostic case 'c': 34631002Sbostic initfile = optarg; 34731002Sbostic break; 34831002Sbostic case 'e': 34931002Sbostic traceexec = true; 35031002Sbostic break; 35131002Sbostic case 'i': 35231002Sbostic interactive = true; 35331002Sbostic break; 35431002Sbostic case 'k': 35531002Sbostic vaddrs = true; 35631002Sbostic break; 35731002Sbostic case 'l': 35831002Sbostic #ifdef LEXDEBUG 35931002Sbostic lexdebug = true; 36031002Sbostic #else 36131002Sbostic fatal("\"-l\" only applicable when compiled with LEXDEBUG"); 36231002Sbostic #endif 36331002Sbostic break; 36431002Sbostic case 'n': 36531002Sbostic traceblocks = true; 36631002Sbostic break; 36733322Sdonn case 'q': 36833322Sdonn quiet = true; 36933322Sdonn break; 37031002Sbostic case 'r': /* run program before accepting commands */ 37131002Sbostic runfirst = true; 3729669Slinton coredump = false; 37331002Sbostic break; 37431002Sbostic case 's': 37531002Sbostic tracesyms = true; 37631002Sbostic break; 37731002Sbostic case '?': 37831002Sbostic default: 37931002Sbostic fatal("unknown option"); 38031002Sbostic } 38131002Sbostic argv += optind; 38231002Sbostic if (*argv) { 38331002Sbostic objname = *argv; 38431002Sbostic if (*++argv && coredump) { 38531002Sbostic corename = *argv; 38631002Sbostic corefile = fopen(*argv, "r"); 38731002Sbostic if (corefile == nil) 38831002Sbostic coredump = false; 38931002Sbostic ++argv; 3909669Slinton } 3919669Slinton } 39233322Sdonn if (*argv and not runfirst) { 39331002Sbostic fatal("extraneous argument %s", *argv); 39433322Sdonn } 39533322Sdonn return argv; 39633322Sdonn } 39733322Sdonn 39833322Sdonn private openfiles () 39933322Sdonn { 40033322Sdonn File f; 40133322Sdonn char *tmp; 40233322Sdonn 40333322Sdonn if (objname == nil and isatty(0)) { 4049669Slinton printf("enter object file name (default is `%s'): ", objname); 4059669Slinton fflush(stdout); 4069669Slinton gets(namebuf); 4079669Slinton if (namebuf[0] != '\0') { 4089669Slinton objname = namebuf; 4099669Slinton } 4109669Slinton } 4119669Slinton f = fopen(objname, "r"); 4129669Slinton if (f == nil) { 4139669Slinton fatal("can't read %s", objname); 4149669Slinton } else { 4159669Slinton fclose(f); 4169669Slinton } 4179669Slinton if (rindex(objname, '/') != nil) { 4189669Slinton tmp = strdup(objname); 4199669Slinton *(rindex(tmp, '/')) = '\0'; 4209669Slinton list_append(list_item(tmp), nil, sourcepath); 4219669Slinton } 4229669Slinton if (coredump and corefile == nil) { 42318223Slinton if (vaddrs) { 42437790Sbostic corename = _PATH_MEM; 42531002Sbostic corefile = fopen(corename, "r"); 42618223Slinton if (corefile == nil) { 42737790Sbostic panic("can't open %s", _PATH_MEM); 42818223Slinton } 42918223Slinton } else { 43018223Slinton corename = "core"; 43131002Sbostic corefile = fopen(corename, "r"); 43218223Slinton if (corefile == nil) { 43318223Slinton coredump = false; 43418223Slinton } 4359669Slinton } 4369669Slinton } 4379669Slinton } 4389669Slinton 4399669Slinton /* 44011868Slinton * Save/restore the state of a tty. 44111868Slinton */ 44211868Slinton 44311868Slinton public savetty(f, t) 44411868Slinton File f; 44511868Slinton Ttyinfo *t; 44611868Slinton { 44733322Sdonn # ifdef IRIS 44833322Sdonn ioctl(fileno(f), TCGETA, t); 44933322Sdonn # else 45033322Sdonn ioctl(fileno(f), TIOCGETP, &(t->sg)); 45133322Sdonn ioctl(fileno(f), TIOCGETC, &(t->tc)); 45233322Sdonn ioctl(fileno(f), TIOCGLTC, &(t->ltc)); 45333322Sdonn ioctl(fileno(f), TIOCGETD, &(t->ldisc)); 45433322Sdonn ioctl(fileno(f), TIOCLGET, &(t->local)); 45533322Sdonn t->fcflags = fcntl(fileno(f), F_GETFL, 0); 45633322Sdonn if ((t->fcflags&FASYNC) != 0) { 45733322Sdonn /* fprintf(stderr, "[async i/o found set -- reset]\n"); */ 45833322Sdonn t->fcflags &= ~FASYNC; 45933322Sdonn } 46033322Sdonn # endif 46111868Slinton } 46211868Slinton 46311868Slinton public restoretty(f, t) 46411868Slinton File f; 46511868Slinton Ttyinfo *t; 46611868Slinton { 46733322Sdonn # ifdef IRIS 46833322Sdonn ioctl(fileno(f), TCSETA, t); 46933322Sdonn # else 47033322Sdonn ioctl(fileno(f), TIOCSETN, &(t->sg)); 47133322Sdonn ioctl(fileno(f), TIOCSETC, &(t->tc)); 47233322Sdonn ioctl(fileno(f), TIOCSLTC, &(t->ltc)); 47333322Sdonn ioctl(fileno(f), TIOCSETD, &(t->ldisc)); 47433322Sdonn ioctl(fileno(f), TIOCLSET, &(t->local)); 47533322Sdonn if ((t->fcflags&FASYNC) != 0) { 47633322Sdonn /* fprintf(stderr, "[async i/o not set]\n"); */ 47733322Sdonn t->fcflags &= ~FASYNC; 47833322Sdonn } 47933322Sdonn (void) fcntl(fileno(f), F_SETFL, t->fcflags); 48033322Sdonn # endif 48111868Slinton } 48211868Slinton 48311868Slinton /* 4849669Slinton * Exit gracefully. 4859669Slinton */ 4869669Slinton 4879669Slinton public quit(r) 4889669Slinton Integer r; 4899669Slinton { 49016613Ssam pterm(process); 4919669Slinton exit(r); 4929669Slinton } 493