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