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