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