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