xref: /csrg-svn/old/dbx/main.c (revision 26328)
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.2 (Berkeley) 02/22/86";
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     optab_init();
107     if (runfirst) {
108 	if (setjmp(env) == FIRST_TIME) {
109 	    arginit();
110 	    for (i = firstarg; i < argc; i++) {
111 		newarg(argv[i]);
112 	    }
113 	    run();
114 	    /* NOTREACHED */
115 	} else {
116 	    runfirst = false;
117 	}
118     } else {
119 	init();
120     }
121     if (setjmp(env) != FIRST_TIME) {
122 	restoretty(stdout, &ttyinfo);
123     }
124     signal(SIGINT, catchintr);
125     yyparse();
126     putchar('\n');
127     quit(0);
128 }
129 
130 /*
131  * Initialize the world, including setting initial input file
132  * if the file exists.
133  */
134 
135 public init()
136 {
137     File f;
138     String home;
139     char buf[100];
140     extern String getenv();
141 
142     savetty(stdout, &ttyinfo);
143     enterkeywords();
144     scanner_init();
145     if (not coredump and not runfirst) {
146 	start(nil, nil, nil);
147     }
148     printf("reading symbolic information ...");
149     fflush(stdout);
150     readobj(objname);
151     printf("\n");
152     fflush(stdout);
153     if (coredump) {
154 	printf("[using memory image in %s]\n", corename);
155 	if (vaddrs) {
156 	    coredump_getkerinfo();
157 	}
158 	setcurfunc(whatblock(pc));
159     } else {
160 	setcurfunc(program);
161     }
162     bpinit();
163     f = fopen(initfile, "r");
164     if (f != nil) {
165 	fclose(f);
166 	setinput(initfile);
167     } else {
168 	home = getenv("HOME");
169 	if (home != nil) {
170 	    sprintf(buf, "%s/%s", home, initfile);
171 	    f = fopen(buf, "r");
172 	    if (f != nil) {
173 		fclose(f);
174 		setinput(strdup(buf));
175 	    }
176 	}
177     }
178     initdone = true;
179 }
180 
181 /*
182  * Re-initialize the world, first de-allocating all storage.
183  * This is necessary when the symbol information must be re-read
184  * from the object file when it has changed.
185  *
186  * Before "forgetting" things, we save the current tracing/breakpoint
187  * information to a temp file.  Then after re-creating the world,
188  * we read the temp file as commands.  This isn't always the right thing;
189  * if a procedure that was being traced is deleted, an error message
190  * will be generated.
191  *
192  * If the argument vector is not nil, then this is re-initialize is being
193  * done in preparation for running the program.  Since we want to process
194  * the commands in the temp file before running the program, we add the
195  * run command at the end of the temp file.  In this case, reinit longjmps
196  * back to parsing rather than returning.
197  */
198 
199 public reinit(argv, infile, outfile)
200 String *argv;
201 String infile;
202 String outfile;
203 {
204     register Integer i;
205     String tmpfile;
206     extern String mktemp();
207 
208     tmpfile = mktemp("/tmp/dbxXXXX");
209     setout(tmpfile);
210     status();
211     alias(nil, nil, nil);
212     if (argv != nil) {
213 	printf("run");
214 	for (i = 1; argv[i] != nil; i++) {
215 	    printf(" %s", argv[i]);
216 	}
217 	if (infile != nil) {
218 	    printf(" < %s", infile);
219 	}
220 	if (outfile != nil) {
221 	    printf(" > %s", outfile);
222 	}
223 	putchar('\n');
224     }
225     unsetout();
226     bpfree();
227     objfree();
228     symbols_init();
229     process_init();
230     enterkeywords();
231     scanner_init();
232     readobj(objname);
233     bpinit();
234     fflush(stdout);
235     setinput(tmpfile);
236     unlink(tmpfile);
237     if (argv != nil) {
238 	longjmp(env, 1);
239 	/* NOTREACHED */
240     }
241 }
242 
243 /*
244  * After a non-fatal error we skip the rest of the current input line, and
245  * jump back to command parsing.
246  */
247 
248 public erecover()
249 {
250     if (initdone) {
251 	gobble();
252 	longjmp(env, 1);
253     }
254 }
255 
256 /*
257  * This routine is called when an interrupt occurs.
258  */
259 
260 private catchintr()
261 {
262     if (isredirected()) {
263 	fflush(stdout);
264 	unsetout();
265     }
266     putchar('\n');
267     longjmp(env, 1);
268 }
269 
270 /*
271  * Scan the argument list.
272  */
273 
274 private scanargs(argc, argv)
275 int argc;
276 String argv[];
277 {
278     register int i, j;
279     register Boolean foundfile;
280     register File f;
281     char *tmp;
282 
283     runfirst = false;
284     interactive = false;
285     lexdebug = false;
286     tracebpts = false;
287     traceexec = false;
288     tracesyms = false;
289     traceblocks = false;
290     vaddrs = false;
291     foundfile = false;
292     corefile = nil;
293     coredump = true;
294     sourcepath = list_alloc();
295     list_append(list_item("."), nil, sourcepath);
296     i = 1;
297     while (i < argc and (not foundfile or (coredump and corefile == nil))) {
298 	if (argv[i][0] == '-') {
299 	    if (streq(argv[i], "-I")) {
300 		++i;
301 		if (i >= argc) {
302 		    fatal("missing directory for -I");
303 		}
304 		list_append(list_item(argv[i]), nil, sourcepath);
305 	    } else if (streq(argv[i], "-c")) {
306 		++i;
307 		if (i >= argc) {
308 		    fatal("missing command file name for -c");
309 		}
310 		initfile = argv[i];
311 	    } else {
312 		for (j = 1; argv[i][j] != '\0'; j++) {
313 		    setoption(argv[i][j]);
314 		}
315 	    }
316 	} else if (not foundfile) {
317 	    objname = argv[i];
318 	    foundfile = true;
319 	} else if (coredump and corefile == nil) {
320 	    corefile = fopen(argv[i], "r");
321 	    corename = argv[i];
322 	    if (corefile == nil) {
323 		coredump = false;
324 	    }
325 	}
326 	++i;
327     }
328     if (i < argc and not runfirst) {
329 	fatal("extraneous argument %s", argv[i]);
330     }
331     firstarg = i;
332     if (not foundfile and isatty(0)) {
333 	printf("enter object file name (default is `%s'): ", objname);
334 	fflush(stdout);
335 	gets(namebuf);
336 	if (namebuf[0] != '\0') {
337 	    objname = namebuf;
338 	}
339     }
340     f = fopen(objname, "r");
341     if (f == nil) {
342 	fatal("can't read %s", objname);
343     } else {
344 	fclose(f);
345     }
346     if (rindex(objname, '/') != nil) {
347 	tmp = strdup(objname);
348 	*(rindex(tmp, '/')) = '\0';
349 	list_append(list_item(tmp), nil, sourcepath);
350     }
351     if (coredump and corefile == nil) {
352 	if (vaddrs) {
353 	    corefile = fopen("/dev/mem", "r");
354 	    corename = "/dev/mem";
355 	    if (corefile == nil) {
356 		panic("can't open /dev/mem");
357 	    }
358 	} else {
359 	    corefile = fopen("core", "r");
360 	    corename = "core";
361 	    if (corefile == nil) {
362 		coredump = false;
363 	    }
364 	}
365     }
366 }
367 
368 /*
369  * Take appropriate action for recognized command argument.
370  */
371 
372 private setoption(c)
373 char c;
374 {
375     switch (c) {
376 	case 'r':   /* run program before accepting commands */
377 	    runfirst = true;
378 	    coredump = false;
379 	    break;
380 
381 	case 'i':
382 	    interactive = true;
383 	    break;
384 
385 	case 'b':
386 	    tracebpts = true;
387 	    break;
388 
389 	case 'e':
390 	    traceexec = true;
391 	    break;
392 
393 	case 's':
394 	    tracesyms = true;
395 	    break;
396 
397 	case 'n':
398 	    traceblocks = true;
399 	    break;
400 
401 	case 'k':
402 	    vaddrs = true;
403 	    break;
404 
405 	case 'l':
406 #   	    ifdef LEXDEBUG
407 		lexdebug = true;
408 #	    else
409 		fatal("\"-l\" only applicable when compiled with LEXDEBUG");
410 #	    endif
411 	    break;
412 
413 	default:
414 	    fatal("unknown option '%c'", c);
415     }
416 }
417 
418 /*
419  * Save/restore the state of a tty.
420  */
421 
422 public savetty(f, t)
423 File f;
424 Ttyinfo *t;
425 {
426     ioctl(fileno(f), TIOCGETP, &(t->sg));
427     ioctl(fileno(f), TIOCGETC, &(t->tc));
428     ioctl(fileno(f), TIOCGLTC, &(t->ltc));
429     ioctl(fileno(f), TIOCGETD, &(t->ldisc));
430     ioctl(fileno(f), TIOCLGET, &(t->local));
431     t->fcflags = fcntl(fileno(f), F_GETFL, 0);
432 }
433 
434 public restoretty(f, t)
435 File f;
436 Ttyinfo *t;
437 {
438     ioctl(fileno(f), TIOCSETN, &(t->sg));
439     ioctl(fileno(f), TIOCSETC, &(t->tc));
440     ioctl(fileno(f), TIOCSLTC, &(t->ltc));
441     ioctl(fileno(f), TIOCSETD, &(t->ldisc));
442     ioctl(fileno(f), TIOCLSET, &(t->local));
443     (void) fcntl(fileno(f), F_SETFL, t->fcflags);
444 }
445 
446 /*
447  * Exit gracefully.
448  */
449 
450 public quit(r)
451 Integer r;
452 {
453     pterm(process);
454     exit(r);
455 }
456