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