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