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
main(argc,argv)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
printheading()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
init()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
reinit(argv,infile,outfile)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
erecover()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
catchintr()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
scanargs(argc,argv)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
openfiles()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
savetty(f,t)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
restoretty(f,t)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
quit(r)477 public quit(r)
478 Integer r;
479 {
480 pterm(process);
481 exit(r);
482 }
483