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