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