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