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