xref: /original-bsd/old/dbx/main.c (revision f0fd5f8a)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)main.c 1.2 12/15/82";
4 
5 /*
6  * Debugger main routine.
7  */
8 
9 #include "defs.h"
10 #include <setjmp.h>
11 #include <signal.h>
12 #include <errno.h>
13 #include "main.h"
14 #include "scanner.h"
15 #include "process.h"
16 #include "source.h"
17 #include "object.h"
18 
19 #ifndef public
20 
21 #define isterm(file)	(interactive or isatty(fileno(file)))
22 
23 #endif
24 
25 public Boolean coredump;		/* true if using a core dump */
26 public Boolean runfirst;		/* run program immediately */
27 public Boolean interactive;		/* standard input IS a terminal */
28 public Boolean lexdebug;		/* trace yylex return values */
29 public Boolean tracebpts;		/* trace create/delete breakpoints */
30 public Boolean traceexec;		/* trace process execution */
31 public Boolean tracesyms;		/* print symbols as their read */
32 
33 public File corefile;			/* File id of core dump */
34 
35 #define FIRST_TIME 0			/* initial value setjmp returns */
36 
37 private Boolean initdone = false;	/* true if initialization done */
38 private jmp_buf env;			/* setjmp/longjmp data */
39 private char outbuf[BUFSIZ];		/* standard output buffer */
40 private char namebuf[512];		/* possible name of object file */
41 private int firstarg;			/* first program argument (for -r) */
42 
43 private catchintr();
44 
45 /*
46  * Main program.
47  */
48 
49 main(argc, argv)
50 int argc;
51 String argv[];
52 {
53     register Integer i;
54 
55     cmdname = argv[0];
56     catcherrs();
57     onsyserr(EINTR, nil);
58     setbuf(stdout, outbuf);
59     scanargs(argc, argv);
60     language_init();
61     process_init();
62     if (runfirst) {
63 	if (setjmp(env) == FIRST_TIME) {
64 	    arginit();
65 	    for (i = firstarg; i < argc; i++) {
66 		newarg(argv[i]);
67 	    }
68 	    run();
69 	    /* NOTREACHED */
70 	} else {
71 	    runfirst = false;
72 	}
73     } else {
74 	init();
75     }
76     setjmp(env);
77     signal(SIGINT, catchintr);
78     yyparse();
79     putchar('\n');
80     quit(0);
81 }
82 
83 /*
84  * Initialize the world, including setting initial input file
85  * if the file exists.
86  */
87 
88 public init()
89 {
90     File f;
91     String home;
92     char buf[100];
93     extern String getenv();
94 
95     enterkeywords();
96     scanner_init();
97     if (not coredump and not runfirst) {
98 	start(nil, nil, nil);
99     }
100     readobj(objname);
101     curfunc = program;
102     bpinit();
103     f = fopen(initfile, "r");
104     if (f != nil) {
105 	fclose(f);
106 	setinput(initfile);
107     } else {
108 	home = getenv("HOME");
109 	if (home != nil) {
110 	    sprintf(buf, "%s/%s", home, initfile);
111 	    f = fopen(buf, "r");
112 	    if (f != nil) {
113 		fclose(f);
114 		setinput(strdup(buf));
115 	    }
116 	}
117     }
118     initdone = true;
119 }
120 
121 /*
122  * Re-initialize the world, first de-allocating all storage.
123  * This is necessary when the symbol information must be re-read
124  * from the object file when it has changed.
125  *
126  * Before "forgetting" things, we save the current tracing/breakpoint
127  * information to a temp file.  Then after re-creating the world,
128  * we read the temp file as commands.  This isn't always the right thing;
129  * if a procedure that was being traced is deleted, an error message
130  * will be generated.
131  *
132  * If the argument vector is not nil, then this is re-initialize is being
133  * done in preparation for running the program.  Since we want to process
134  * the commands in the temp file before running the program, we add the
135  * run command at the end of the temp file.  In this case, reinit longjmps
136  * back to parsing rather than returning.
137  */
138 
139 public reinit(argv, infile, outfile)
140 String *argv;
141 String infile;
142 String outfile;
143 {
144     register Integer i;
145     String tmpfile;
146     extern String mktemp();
147 
148     tmpfile = mktemp("/tmp/dbxXXXX");
149     setout(tmpfile);
150     status();
151     print_alias(nil);
152     if (argv != nil) {
153 	printf("run");
154 	for (i = 1; argv[i] != nil; i++) {
155 	    printf(" %s", argv[i]);
156 	}
157 	if (infile != nil) {
158 	    printf(" < %s", infile);
159 	}
160 	if (outfile != nil) {
161 	    printf(" > %s", outfile);
162 	}
163 	putchar('\n');
164     }
165     unsetout();
166     bpfree();
167     objfree();
168     process_init();
169     enterkeywords();
170     scanner_init();
171     readobj(objname);
172     bpinit();
173     fflush(stdout);
174     setinput(tmpfile);
175     unlink(tmpfile);
176     if (argv != nil) {
177 	longjmp(env, 1);
178 	/* NOTREACHED */
179     }
180 }
181 
182 /*
183  * After a non-fatal error we jump back to command parsing.
184  */
185 
186 public erecover()
187 {
188     if (initdone) {
189 	gobble();
190 	longjmp(env, 1);
191     }
192 }
193 
194 /*
195  * This routine is called when an interrupt occurs.
196  */
197 
198 private catchintr()
199 {
200     putchar('\n');
201     longjmp(env, 1);
202 }
203 
204 /*
205  * Scan the argument list.
206  */
207 
208 private scanargs(argc, argv)
209 int argc;
210 String argv[];
211 {
212     register int i, j;
213     register Boolean foundfile;
214     register File f;
215     char *tmp;
216 
217     runfirst = false;
218     interactive = false;
219     lexdebug = false;
220     tracebpts = false;
221     traceexec = false;
222     tracesyms = false;
223     foundfile = false;
224     corefile = nil;
225     coredump = true;
226     sourcepath = list_alloc();
227     list_append(list_item("."), nil, sourcepath);
228     i = 1;
229     while (i < argc and not foundfile and corefile == nil) {
230 	if (argv[i][0] == '-') {
231 	    if (streq(argv[i], "-I")) {
232 		++i;
233 		if (i >= argc) {
234 		    fatal("missing directory for -I");
235 		}
236 		list_append(list_item(argv[i]), nil, sourcepath);
237 	    } else {
238 		for (j = 1; argv[i][j] != '\0'; j++) {
239 		    setoption(argv[i][j]);
240 		}
241 	    }
242 	} else if (not foundfile) {
243 	    objname = argv[i];
244 	    foundfile = true;
245 	} else if (coredump and corefile == nil) {
246 	    corefile = fopen(argv[i], "r");
247 	    if (corefile == nil) {
248 		coredump = false;
249 	    }
250 	}
251 	++i;
252     }
253     if (i < argc and not runfirst) {
254 	fatal("extraneous argument %s", argv[i]);
255     }
256     firstarg = i;
257     if (not foundfile and isatty(0)) {
258 	printf("enter object file name (default is `%s'): ", objname);
259 	fflush(stdout);
260 	gets(namebuf);
261 	if (namebuf[0] != '\0') {
262 	    objname = namebuf;
263 	}
264     }
265     f = fopen(objname, "r");
266     if (f == nil) {
267 	fatal("can't read %s", objname);
268     } else {
269 	fclose(f);
270     }
271     if (rindex(objname, '/') != nil) {
272 	tmp = strdup(objname);
273 	*(rindex(tmp, '/')) = '\0';
274 	list_append(list_item(tmp), nil, sourcepath);
275     }
276     if (coredump and corefile == nil) {
277 	corefile = fopen("core", "r");
278 	if (corefile == nil) {
279 	    coredump = false;
280 	}
281     }
282 }
283 
284 /*
285  * Take appropriate action for recognized command argument.
286  */
287 
288 private setoption(c)
289 char c;
290 {
291     switch (c) {
292 	case 'r':   /* run program before accepting commands */
293 	    runfirst = true;
294 	    coredump = false;
295 	    break;
296 
297 	case 'i':
298 	    interactive = true;
299 	    break;
300 
301 	case 'b':
302 	    tracebpts = true;
303 	    break;
304 
305 	case 'e':
306 	    traceexec = true;
307 	    break;
308 
309 	case 's':
310 	    tracesyms = true;
311 	    break;
312 
313 	case 'l':
314 #   	    ifdef LEXDEBUG
315 		lexdebug = true;
316 #	    else
317 		fatal("\"-l\" only applicable when compiled with LEXDEBUG");
318 #	    endif
319 	    break;
320 
321 	default:
322 	    fatal("unknown option '%c'", c);
323     }
324 }
325 
326 /*
327  * Exit gracefully.
328  */
329 
330 public quit(r)
331 Integer r;
332 {
333     exit(r);
334 }
335