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