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