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