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