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