1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)main.c 5.1 (Berkeley) 05/31/85"; 15 #endif not lint 16 17 static char rcsid[] = "$Header: main.c,v 1.5 84/12/26 10:40:16 linton Exp $"; 18 19 /* 20 * Debugger main routine. 21 */ 22 23 #include "defs.h" 24 #include <setjmp.h> 25 #include <signal.h> 26 #include <errno.h> 27 #include "main.h" 28 #include "eval.h" 29 #include "debug.h" 30 #include "symbols.h" 31 #include "scanner.h" 32 #include "keywords.h" 33 #include "process.h" 34 #include "runtime.h" 35 #include "source.h" 36 #include "object.h" 37 #include "mappings.h" 38 #include "coredump.h" 39 40 #ifndef public 41 42 #define isterm(file) (interactive or isatty(fileno(file))) 43 44 #include <sgtty.h> 45 #include <fcntl.h> 46 47 typedef struct { 48 struct sgttyb sg; /* standard sgttyb structure */ 49 struct tchars tc; /* terminal characters */ 50 struct ltchars ltc; /* local special characters */ 51 integer ldisc; /* line discipline */ 52 integer local; /* TIOCLGET */ 53 integer fcflags; /* fcntl(2) F_GETFL, F_SETFL */ 54 } Ttyinfo; 55 56 #endif 57 58 public boolean coredump; /* true if using a core dump */ 59 public boolean runfirst; /* run program immediately */ 60 public boolean interactive; /* standard input IS a terminal */ 61 public boolean lexdebug; /* trace scanner return values */ 62 public boolean tracebpts; /* trace create/delete breakpoints */ 63 public boolean traceexec; /* trace execution */ 64 public boolean tracesyms; /* print symbols are they are read */ 65 public boolean traceblocks; /* trace blocks while reading symbols */ 66 public boolean vaddrs; /* map addresses through page tables */ 67 68 public File corefile; /* File id of core dump */ 69 70 #define FIRST_TIME 0 /* initial value setjmp returns */ 71 72 private Boolean initdone = false; /* true if initialization done */ 73 private jmp_buf env; /* setjmp/longjmp data */ 74 private char outbuf[BUFSIZ]; /* standard output buffer */ 75 private char namebuf[512]; /* possible name of object file */ 76 private int firstarg; /* first program argument (for -r) */ 77 78 private Ttyinfo ttyinfo; 79 private String corename; /* name of core file */ 80 81 private catchintr(); 82 83 /* 84 * Main program. 85 */ 86 87 main(argc, argv) 88 int argc; 89 String argv[]; 90 { 91 register integer i; 92 extern String date; 93 extern integer versionNumber; 94 95 cmdname = argv[0]; 96 catcherrs(); 97 onsyserr(EINTR, nil); 98 setbuf(stdout, outbuf); 99 printf("dbx version 3.%d of %s.\nType 'help' for help.\n", 100 versionNumber, date); 101 fflush(stdout); 102 scanargs(argc, argv); 103 language_init(); 104 symbols_init(); 105 process_init(); 106 if (runfirst) { 107 if (setjmp(env) == FIRST_TIME) { 108 arginit(); 109 for (i = firstarg; i < argc; i++) { 110 newarg(argv[i]); 111 } 112 run(); 113 /* NOTREACHED */ 114 } else { 115 runfirst = false; 116 } 117 } else { 118 init(); 119 } 120 if (setjmp(env) != FIRST_TIME) { 121 restoretty(stdout, &ttyinfo); 122 } 123 signal(SIGINT, catchintr); 124 yyparse(); 125 putchar('\n'); 126 quit(0); 127 } 128 129 /* 130 * Initialize the world, including setting initial input file 131 * if the file exists. 132 */ 133 134 public init() 135 { 136 File f; 137 String home; 138 char buf[100]; 139 extern String getenv(); 140 141 savetty(stdout, &ttyinfo); 142 enterkeywords(); 143 scanner_init(); 144 if (not coredump and not runfirst) { 145 start(nil, nil, nil); 146 } 147 printf("reading symbolic information ..."); 148 fflush(stdout); 149 readobj(objname); 150 printf("\n"); 151 fflush(stdout); 152 if (coredump) { 153 printf("[using memory image in %s]\n", corename); 154 if (vaddrs) { 155 coredump_getkerinfo(); 156 } 157 setcurfunc(whatblock(pc)); 158 } else { 159 setcurfunc(program); 160 } 161 bpinit(); 162 f = fopen(initfile, "r"); 163 if (f != nil) { 164 fclose(f); 165 setinput(initfile); 166 } else { 167 home = getenv("HOME"); 168 if (home != nil) { 169 sprintf(buf, "%s/%s", home, initfile); 170 f = fopen(buf, "r"); 171 if (f != nil) { 172 fclose(f); 173 setinput(strdup(buf)); 174 } 175 } 176 } 177 initdone = true; 178 } 179 180 /* 181 * Re-initialize the world, first de-allocating all storage. 182 * This is necessary when the symbol information must be re-read 183 * from the object file when it has changed. 184 * 185 * Before "forgetting" things, we save the current tracing/breakpoint 186 * information to a temp file. Then after re-creating the world, 187 * we read the temp file as commands. This isn't always the right thing; 188 * if a procedure that was being traced is deleted, an error message 189 * will be generated. 190 * 191 * If the argument vector is not nil, then this is re-initialize is being 192 * done in preparation for running the program. Since we want to process 193 * the commands in the temp file before running the program, we add the 194 * run command at the end of the temp file. In this case, reinit longjmps 195 * back to parsing rather than returning. 196 */ 197 198 public reinit(argv, infile, outfile) 199 String *argv; 200 String infile; 201 String outfile; 202 { 203 register Integer i; 204 String tmpfile; 205 extern String mktemp(); 206 207 tmpfile = mktemp("/tmp/dbxXXXX"); 208 setout(tmpfile); 209 status(); 210 alias(nil, nil, nil); 211 if (argv != nil) { 212 printf("run"); 213 for (i = 1; argv[i] != nil; i++) { 214 printf(" %s", argv[i]); 215 } 216 if (infile != nil) { 217 printf(" < %s", infile); 218 } 219 if (outfile != nil) { 220 printf(" > %s", outfile); 221 } 222 putchar('\n'); 223 } 224 unsetout(); 225 bpfree(); 226 objfree(); 227 symbols_init(); 228 process_init(); 229 enterkeywords(); 230 scanner_init(); 231 readobj(objname); 232 bpinit(); 233 fflush(stdout); 234 setinput(tmpfile); 235 unlink(tmpfile); 236 if (argv != nil) { 237 longjmp(env, 1); 238 /* NOTREACHED */ 239 } 240 } 241 242 /* 243 * After a non-fatal error we skip the rest of the current input line, and 244 * jump back to command parsing. 245 */ 246 247 public erecover() 248 { 249 if (initdone) { 250 gobble(); 251 longjmp(env, 1); 252 } 253 } 254 255 /* 256 * This routine is called when an interrupt occurs. 257 */ 258 259 private catchintr() 260 { 261 if (isredirected()) { 262 fflush(stdout); 263 unsetout(); 264 } 265 putchar('\n'); 266 longjmp(env, 1); 267 } 268 269 /* 270 * Scan the argument list. 271 */ 272 273 private scanargs(argc, argv) 274 int argc; 275 String argv[]; 276 { 277 register int i, j; 278 register Boolean foundfile; 279 register File f; 280 char *tmp; 281 282 runfirst = false; 283 interactive = false; 284 lexdebug = false; 285 tracebpts = false; 286 traceexec = false; 287 tracesyms = false; 288 traceblocks = false; 289 vaddrs = false; 290 foundfile = false; 291 corefile = nil; 292 coredump = true; 293 sourcepath = list_alloc(); 294 list_append(list_item("."), nil, sourcepath); 295 i = 1; 296 while (i < argc and (not foundfile or (coredump and corefile == nil))) { 297 if (argv[i][0] == '-') { 298 if (streq(argv[i], "-I")) { 299 ++i; 300 if (i >= argc) { 301 fatal("missing directory for -I"); 302 } 303 list_append(list_item(argv[i]), nil, sourcepath); 304 } else if (streq(argv[i], "-c")) { 305 ++i; 306 if (i >= argc) { 307 fatal("missing command file name for -c"); 308 } 309 initfile = argv[i]; 310 } else { 311 for (j = 1; argv[i][j] != '\0'; j++) { 312 setoption(argv[i][j]); 313 } 314 } 315 } else if (not foundfile) { 316 objname = argv[i]; 317 foundfile = true; 318 } else if (coredump and corefile == nil) { 319 corefile = fopen(argv[i], "r"); 320 corename = argv[i]; 321 if (corefile == nil) { 322 coredump = false; 323 } 324 } 325 ++i; 326 } 327 if (i < argc and not runfirst) { 328 fatal("extraneous argument %s", argv[i]); 329 } 330 firstarg = i; 331 if (not foundfile and isatty(0)) { 332 printf("enter object file name (default is `%s'): ", objname); 333 fflush(stdout); 334 gets(namebuf); 335 if (namebuf[0] != '\0') { 336 objname = namebuf; 337 } 338 } 339 f = fopen(objname, "r"); 340 if (f == nil) { 341 fatal("can't read %s", objname); 342 } else { 343 fclose(f); 344 } 345 if (rindex(objname, '/') != nil) { 346 tmp = strdup(objname); 347 *(rindex(tmp, '/')) = '\0'; 348 list_append(list_item(tmp), nil, sourcepath); 349 } 350 if (coredump and corefile == nil) { 351 if (vaddrs) { 352 corefile = fopen("/dev/mem", "r"); 353 corename = "/dev/mem"; 354 if (corefile == nil) { 355 panic("can't open /dev/mem"); 356 } 357 } else { 358 corefile = fopen("core", "r"); 359 corename = "core"; 360 if (corefile == nil) { 361 coredump = false; 362 } 363 } 364 } 365 } 366 367 /* 368 * Take appropriate action for recognized command argument. 369 */ 370 371 private setoption(c) 372 char c; 373 { 374 switch (c) { 375 case 'r': /* run program before accepting commands */ 376 runfirst = true; 377 coredump = false; 378 break; 379 380 case 'i': 381 interactive = true; 382 break; 383 384 case 'b': 385 tracebpts = true; 386 break; 387 388 case 'e': 389 traceexec = true; 390 break; 391 392 case 's': 393 tracesyms = true; 394 break; 395 396 case 'n': 397 traceblocks = true; 398 break; 399 400 case 'k': 401 vaddrs = true; 402 break; 403 404 case 'l': 405 # ifdef LEXDEBUG 406 lexdebug = true; 407 # else 408 fatal("\"-l\" only applicable when compiled with LEXDEBUG"); 409 # endif 410 break; 411 412 default: 413 fatal("unknown option '%c'", c); 414 } 415 } 416 417 /* 418 * Save/restore the state of a tty. 419 */ 420 421 public savetty(f, t) 422 File f; 423 Ttyinfo *t; 424 { 425 ioctl(fileno(f), TIOCGETP, &(t->sg)); 426 ioctl(fileno(f), TIOCGETC, &(t->tc)); 427 ioctl(fileno(f), TIOCGLTC, &(t->ltc)); 428 ioctl(fileno(f), TIOCGETD, &(t->ldisc)); 429 ioctl(fileno(f), TIOCLGET, &(t->local)); 430 t->fcflags = fcntl(fileno(f), F_GETFL, 0); 431 } 432 433 public restoretty(f, t) 434 File f; 435 Ttyinfo *t; 436 { 437 ioctl(fileno(f), TIOCSETN, &(t->sg)); 438 ioctl(fileno(f), TIOCSETC, &(t->tc)); 439 ioctl(fileno(f), TIOCSLTC, &(t->ltc)); 440 ioctl(fileno(f), TIOCSETD, &(t->ldisc)); 441 ioctl(fileno(f), TIOCLSET, &(t->local)); 442 (void) fcntl(fileno(f), F_SETFL, t->fcflags); 443 } 444 445 /* 446 * Exit gracefully. 447 */ 448 449 public quit(r) 450 Integer r; 451 { 452 pterm(process); 453 exit(r); 454 } 455