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 DF |
13 | #ifndef lint |
14 | static char sccsid[] = "@(#)main.c 5.1 (Berkeley) %G%"; | |
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 ML |
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 | } | |
2fd0f574 SL |
120 | if (setjmp(env) != FIRST_TIME) { |
121 | restoretty(stdout, &ttyinfo); | |
122 | } | |
00102538 ML |
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 | ||
39144fe1 | 141 | savetty(stdout, &ttyinfo); |
00102538 ML |
142 | enterkeywords(); |
143 | scanner_init(); | |
144 | if (not coredump and not runfirst) { | |
145 | start(nil, nil, nil); | |
146 | } | |
39144fe1 ML |
147 | printf("reading symbolic information ..."); |
148 | fflush(stdout); | |
00102538 | 149 | readobj(objname); |
39144fe1 ML |
150 | printf("\n"); |
151 | fflush(stdout); | |
1c5b15ac | 152 | if (coredump) { |
0022c355 ML |
153 | printf("[using memory image in %s]\n", corename); |
154 | if (vaddrs) { | |
155 | coredump_getkerinfo(); | |
156 | } | |
2fd0f574 | 157 | setcurfunc(whatblock(pc)); |
1c5b15ac | 158 | } else { |
2fd0f574 | 159 | setcurfunc(program); |
1c5b15ac | 160 | } |
00102538 ML |
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(); | |
0022c355 | 210 | alias(nil, nil, nil); |
00102538 ML |
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(); | |
0022c355 | 227 | symbols_init(); |
00102538 ML |
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 | /* | |
0022c355 ML |
243 | * After a non-fatal error we skip the rest of the current input line, and |
244 | * jump back to command parsing. | |
00102538 ML |
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 | { | |
0022c355 ML |
261 | if (isredirected()) { |
262 | fflush(stdout); | |
263 | unsetout(); | |
264 | } | |
00102538 ML |
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; | |
2fd0f574 | 288 | traceblocks = false; |
0022c355 | 289 | vaddrs = false; |
00102538 ML |
290 | foundfile = false; |
291 | corefile = nil; | |
292 | coredump = true; | |
293 | sourcepath = list_alloc(); | |
294 | list_append(list_item("."), nil, sourcepath); | |
295 | i = 1; | |
0022c355 | 296 | while (i < argc and (not foundfile or (coredump and corefile == nil))) { |
00102538 ML |
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); | |
0022c355 ML |
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]; | |
00102538 ML |
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"); | |
0022c355 | 320 | corename = argv[i]; |
00102538 ML |
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) { | |
0022c355 ML |
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 | } | |
00102538 ML |
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 | ||
2fd0f574 SL |
396 | case 'n': |
397 | traceblocks = true; | |
398 | break; | |
399 | ||
0022c355 ML |
400 | case 'k': |
401 | vaddrs = true; | |
402 | break; | |
403 | ||
00102538 | 404 | case 'l': |
0022c355 | 405 | # ifdef LEXDEBUG |
00102538 | 406 | lexdebug = true; |
0022c355 ML |
407 | # else |
408 | fatal("\"-l\" only applicable when compiled with LEXDEBUG"); | |
409 | # endif | |
00102538 ML |
410 | break; |
411 | ||
412 | default: | |
413 | fatal("unknown option '%c'", c); | |
414 | } | |
415 | } | |
416 | ||
39144fe1 ML |
417 | /* |
418 | * Save/restore the state of a tty. | |
419 | */ | |
420 | ||
421 | public savetty(f, t) | |
422 | File f; | |
423 | Ttyinfo *t; | |
424 | { | |
d582c82a RC |
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); | |
39144fe1 ML |
431 | } |
432 | ||
433 | public restoretty(f, t) | |
434 | File f; | |
435 | Ttyinfo *t; | |
436 | { | |
d582c82a RC |
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); | |
39144fe1 ML |
443 | } |
444 | ||
00102538 ML |
445 | /* |
446 | * Exit gracefully. | |
447 | */ | |
448 | ||
449 | public quit(r) | |
450 | Integer r; | |
451 | { | |
2fd0f574 | 452 | pterm(process); |
00102538 ML |
453 | exit(r); |
454 | } |