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