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