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