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