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.3 (Berkeley) 05/01/87"; 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 77 private Ttyinfo ttyinfo; 78 private String corename; /* name of core file */ 79 80 private catchintr(); 81 82 /* 83 * Main program. 84 */ 85 86 main(argc, argv) 87 int argc; 88 String argv[]; 89 { 90 register integer i; 91 extern String date; 92 extern integer versionNumber; 93 char **scanargs(); 94 95 if (!(cmdname = rindex(*argv, '/'))) 96 cmdname = *argv; 97 else 98 ++cmdname; 99 100 catcherrs(); 101 onsyserr(EINTR, nil); 102 setbuf(stdout, outbuf); 103 printf("dbx version 3.%d of %s.\nType 'help' for help.\n", 104 versionNumber, date); 105 fflush(stdout); 106 argv = scanargs(argc, argv); 107 language_init(); 108 symbols_init(); 109 process_init(); 110 optab_init(); 111 if (runfirst) { 112 if (setjmp(env) == FIRST_TIME) { 113 arginit(); 114 while (*argv) 115 newarg(*argv++); 116 run(); 117 /* NOTREACHED */ 118 } else { 119 runfirst = false; 120 } 121 } else { 122 init(); 123 } 124 if (setjmp(env) != FIRST_TIME) { 125 restoretty(stdout, &ttyinfo); 126 } 127 signal(SIGINT, catchintr); 128 yyparse(); 129 putchar('\n'); 130 quit(0); 131 } 132 133 /* 134 * Initialize the world, including setting initial input file 135 * if the file exists. 136 */ 137 138 public init() 139 { 140 File f; 141 String home; 142 char buf[100]; 143 extern String getenv(); 144 145 savetty(stdout, &ttyinfo); 146 enterkeywords(); 147 scanner_init(); 148 if (not coredump and not runfirst) { 149 start(nil, nil, nil); 150 } 151 printf("reading symbolic information ..."); 152 fflush(stdout); 153 readobj(objname); 154 printf("\n"); 155 fflush(stdout); 156 if (coredump) { 157 printf("[using memory image in %s]\n", corename); 158 if (vaddrs) { 159 coredump_getkerinfo(); 160 } 161 setcurfunc(whatblock(pc)); 162 } else { 163 setcurfunc(program); 164 } 165 bpinit(); 166 f = fopen(initfile, "r"); 167 if (f != nil) { 168 fclose(f); 169 setinput(initfile); 170 } else { 171 home = getenv("HOME"); 172 if (home != nil) { 173 sprintf(buf, "%s/%s", home, initfile); 174 f = fopen(buf, "r"); 175 if (f != nil) { 176 fclose(f); 177 setinput(strdup(buf)); 178 } 179 } 180 } 181 initdone = true; 182 } 183 184 /* 185 * Re-initialize the world, first de-allocating all storage. 186 * This is necessary when the symbol information must be re-read 187 * from the object file when it has changed. 188 * 189 * Before "forgetting" things, we save the current tracing/breakpoint 190 * information to a temp file. Then after re-creating the world, 191 * we read the temp file as commands. This isn't always the right thing; 192 * if a procedure that was being traced is deleted, an error message 193 * will be generated. 194 * 195 * If the argument vector is not nil, then this is re-initialize is being 196 * done in preparation for running the program. Since we want to process 197 * the commands in the temp file before running the program, we add the 198 * run command at the end of the temp file. In this case, reinit longjmps 199 * back to parsing rather than returning. 200 */ 201 202 public reinit(argv, infile, outfile) 203 String *argv; 204 String infile; 205 String outfile; 206 { 207 register Integer i; 208 String tmpfile; 209 extern String mktemp(); 210 211 tmpfile = mktemp("/tmp/dbxXXXX"); 212 setout(tmpfile); 213 status(); 214 alias(nil, nil, nil); 215 if (argv != nil) { 216 printf("run"); 217 for (i = 1; argv[i] != nil; i++) { 218 printf(" %s", argv[i]); 219 } 220 if (infile != nil) { 221 printf(" < %s", infile); 222 } 223 if (outfile != nil) { 224 printf(" > %s", outfile); 225 } 226 putchar('\n'); 227 } 228 unsetout(); 229 bpfree(); 230 objfree(); 231 symbols_init(); 232 process_init(); 233 enterkeywords(); 234 scanner_init(); 235 readobj(objname); 236 bpinit(); 237 fflush(stdout); 238 setinput(tmpfile); 239 unlink(tmpfile); 240 if (argv != nil) { 241 longjmp(env, 1); 242 /* NOTREACHED */ 243 } 244 } 245 246 /* 247 * After a non-fatal error we skip the rest of the current input line, and 248 * jump back to command parsing. 249 */ 250 251 public erecover() 252 { 253 if (initdone) { 254 gobble(); 255 longjmp(env, 1); 256 } 257 } 258 259 /* 260 * This routine is called when an interrupt occurs. 261 */ 262 263 private catchintr() 264 { 265 if (isredirected()) { 266 fflush(stdout); 267 unsetout(); 268 } 269 putchar('\n'); 270 longjmp(env, 1); 271 } 272 273 /* 274 * Scan the argument list. 275 */ 276 277 private char **scanargs(argc, argv) 278 int argc; 279 String argv[]; 280 { 281 extern char *optarg; 282 extern int optind; 283 register int i, j; 284 register Boolean foundfile; 285 register File f; 286 int ch; 287 char *tmp; 288 289 runfirst = false; 290 interactive = false; 291 lexdebug = false; 292 tracebpts = false; 293 traceexec = false; 294 tracesyms = false; 295 traceblocks = false; 296 vaddrs = false; 297 foundfile = false; 298 corefile = nil; 299 coredump = true; 300 sourcepath = list_alloc(); 301 list_append(list_item("."), nil, sourcepath); 302 303 while ((ch = getopt(argc, argv, "I:bc:eiklnrs")) != EOF) 304 switch((char)ch) { 305 case 'I': 306 list_append(list_item(optarg), nil, sourcepath); 307 break; 308 case 'b': 309 tracebpts = true; 310 break; 311 case 'c': 312 initfile = optarg; 313 break; 314 case 'e': 315 traceexec = true; 316 break; 317 case 'i': 318 interactive = true; 319 break; 320 case 'k': 321 vaddrs = true; 322 break; 323 case 'l': 324 #ifdef LEXDEBUG 325 lexdebug = true; 326 #else 327 fatal("\"-l\" only applicable when compiled with LEXDEBUG"); 328 #endif 329 break; 330 case 'n': 331 traceblocks = true; 332 break; 333 case 'r': /* run program before accepting commands */ 334 runfirst = true; 335 coredump = false; 336 break; 337 case 's': 338 tracesyms = true; 339 break; 340 case '?': 341 default: 342 fatal("unknown option"); 343 } 344 argv += optind; 345 if (*argv) { 346 objname = *argv; 347 foundfile = true; 348 if (*++argv && coredump) { 349 corename = *argv; 350 corefile = fopen(*argv, "r"); 351 if (corefile == nil) 352 coredump = false; 353 ++argv; 354 } 355 } 356 if (*argv and not runfirst) 357 fatal("extraneous argument %s", *argv); 358 if (not foundfile and isatty(0)) { 359 printf("enter object file name (default is `%s'): ", objname); 360 fflush(stdout); 361 gets(namebuf); 362 if (namebuf[0] != '\0') { 363 objname = namebuf; 364 } 365 } 366 f = fopen(objname, "r"); 367 if (f == nil) { 368 fatal("can't read %s", objname); 369 } else { 370 fclose(f); 371 } 372 if (rindex(objname, '/') != nil) { 373 tmp = strdup(objname); 374 *(rindex(tmp, '/')) = '\0'; 375 list_append(list_item(tmp), nil, sourcepath); 376 } 377 if (coredump and corefile == nil) { 378 if (vaddrs) { 379 corename = "/dev/mem"; 380 corefile = fopen(corename, "r"); 381 if (corefile == nil) { 382 panic("can't open /dev/mem"); 383 } 384 } else { 385 corename = "core"; 386 corefile = fopen(corename, "r"); 387 if (corefile == nil) { 388 coredump = false; 389 } 390 } 391 } 392 return(argv); 393 } 394 395 /* 396 * Save/restore the state of a tty. 397 */ 398 399 public savetty(f, t) 400 File f; 401 Ttyinfo *t; 402 { 403 ioctl(fileno(f), TIOCGETP, &(t->sg)); 404 ioctl(fileno(f), TIOCGETC, &(t->tc)); 405 ioctl(fileno(f), TIOCGLTC, &(t->ltc)); 406 ioctl(fileno(f), TIOCGETD, &(t->ldisc)); 407 ioctl(fileno(f), TIOCLGET, &(t->local)); 408 t->fcflags = fcntl(fileno(f), F_GETFL, 0); 409 } 410 411 public restoretty(f, t) 412 File f; 413 Ttyinfo *t; 414 { 415 ioctl(fileno(f), TIOCSETN, &(t->sg)); 416 ioctl(fileno(f), TIOCSETC, &(t->tc)); 417 ioctl(fileno(f), TIOCSLTC, &(t->ltc)); 418 ioctl(fileno(f), TIOCSETD, &(t->ldisc)); 419 ioctl(fileno(f), TIOCLSET, &(t->local)); 420 (void) fcntl(fileno(f), F_SETFL, t->fcflags); 421 } 422 423 /* 424 * Exit gracefully. 425 */ 426 427 public quit(r) 428 Integer r; 429 { 430 pterm(process); 431 exit(r); 432 } 433