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