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