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