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