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