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) 5/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: }