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