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