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