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