]>
Commit | Line | Data |
---|---|---|
754e5da2 SG |
1 | /* TK interface routines. |
2 | Copyright 1994 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GDB. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "symtab.h" | |
22 | #include "inferior.h" | |
23 | #include "command.h" | |
24 | #include "bfd.h" | |
25 | #include "symfile.h" | |
26 | #include "objfiles.h" | |
27 | #include "target.h" | |
754e5da2 SG |
28 | #include <tcl.h> |
29 | #include <tk.h> | |
cd2df226 SG |
30 | #include <varargs.h> |
31 | #include <signal.h> | |
32 | #include <fcntl.h> | |
8532893d | 33 | #include <unistd.h> |
86db943c SG |
34 | #include <setjmp.h> |
35 | #include "top.h" | |
736a82e7 SG |
36 | #include <sys/ioctl.h> |
37 | #include <string.h> | |
38 | ||
39 | #ifndef FIOASYNC | |
546b8ca7 SG |
40 | #include <sys/stropts.h> |
41 | #endif | |
754e5da2 SG |
42 | |
43 | /* Non-zero means that we're doing the gdbtk interface. */ | |
44 | int gdbtk = 0; | |
45 | ||
46 | /* Non-zero means we are reloading breakpoints, etc from the | |
47 | Gdbtk kernel, and we should suppress various messages */ | |
48 | static int gdbtk_reloading = 0; | |
49 | ||
50 | /* Handle for TCL interpreter */ | |
51 | static Tcl_Interp *interp = NULL; | |
52 | ||
53 | /* Handle for TK main window */ | |
54 | static Tk_Window mainWindow = NULL; | |
55 | ||
479f0f18 SG |
56 | static int x_fd; /* X network socket */ |
57 | ||
754e5da2 SG |
58 | static void |
59 | null_routine(arg) | |
60 | int arg; | |
61 | { | |
62 | } | |
63 | ||
546b8ca7 SG |
64 | /* The following routines deal with stdout/stderr data, which is created by |
65 | {f}printf_{un}filtered and friends. gdbtk_fputs and gdbtk_flush are the | |
66 | lowest level of these routines and capture all output from the rest of GDB. | |
67 | Normally they present their data to tcl via callbacks to the following tcl | |
68 | routines: gdbtk_tcl_fputs, gdbtk_tcl_fputs_error, and gdbtk_flush. These | |
69 | in turn call tk routines to update the display. | |
86db943c | 70 | |
546b8ca7 SG |
71 | Under some circumstances, you may want to collect the output so that it can |
72 | be returned as the value of a tcl procedure. This can be done by | |
73 | surrounding the output routines with calls to start_saving_output and | |
74 | finish_saving_output. The saved data can then be retrieved with | |
75 | get_saved_output (but this must be done before the call to | |
76 | finish_saving_output). */ | |
86db943c | 77 | |
546b8ca7 | 78 | /* Dynamic string header for stdout. */ |
86db943c | 79 | |
546b8ca7 | 80 | static Tcl_DString stdout_buffer; |
86db943c | 81 | |
546b8ca7 SG |
82 | /* Use this to collect stdout output that will be returned as the result of a |
83 | tcl command. */ | |
86db943c | 84 | |
546b8ca7 | 85 | static int saving_output = 0; |
86db943c | 86 | |
546b8ca7 SG |
87 | static void |
88 | start_saving_output () | |
89 | { | |
90 | saving_output = 1; | |
86db943c SG |
91 | } |
92 | ||
546b8ca7 | 93 | #define get_saved_output() (Tcl_DStringValue (&stdout_buffer)) |
86db943c SG |
94 | |
95 | static void | |
96 | finish_saving_output () | |
97 | { | |
546b8ca7 | 98 | saving_output = 0; |
86db943c | 99 | |
546b8ca7 | 100 | Tcl_DStringFree (&stdout_buffer); |
86db943c | 101 | } |
754e5da2 SG |
102 | \f |
103 | /* This routine redirects the output of fputs_unfiltered so that | |
104 | the user can see what's going on in his debugger window. */ | |
105 | ||
106 | static void | |
8532893d | 107 | flush_holdbuf () |
754e5da2 | 108 | { |
546b8ca7 SG |
109 | char *s, *argv[1]; |
110 | ||
111 | /* We use Tcl_Merge to quote braces and funny characters as necessary. */ | |
112 | ||
113 | argv[0] = Tcl_DStringValue (&stdout_buffer); | |
114 | s = Tcl_Merge (1, argv); | |
8532893d | 115 | |
546b8ca7 SG |
116 | Tcl_DStringFree (&stdout_buffer); |
117 | ||
118 | Tcl_VarEval (interp, "gdbtk_tcl_fputs ", s, NULL); | |
119 | ||
120 | free (s); | |
754e5da2 SG |
121 | } |
122 | ||
123 | static void | |
124 | gdbtk_flush (stream) | |
125 | FILE *stream; | |
126 | { | |
546b8ca7 | 127 | if (stream != gdb_stdout || saving_output) |
86db943c SG |
128 | return; |
129 | ||
130 | /* Flush output from C to tcl land. */ | |
131 | ||
8532893d SG |
132 | flush_holdbuf (); |
133 | ||
86db943c SG |
134 | /* Force immediate screen update */ |
135 | ||
754e5da2 SG |
136 | Tcl_VarEval (interp, "gdbtk_tcl_flush", NULL); |
137 | } | |
138 | ||
8532893d | 139 | static void |
86db943c | 140 | gdbtk_fputs (ptr, stream) |
8532893d | 141 | const char *ptr; |
86db943c | 142 | FILE *stream; |
8532893d SG |
143 | { |
144 | int len; | |
145 | ||
86db943c SG |
146 | if (stream != gdb_stdout) |
147 | { | |
148 | Tcl_VarEval (interp, "gdbtk_tcl_fputs_error ", "{", ptr, "}", NULL); | |
149 | return; | |
150 | } | |
151 | ||
546b8ca7 | 152 | Tcl_DStringAppend (&stdout_buffer, ptr, -1); |
8532893d | 153 | |
546b8ca7 SG |
154 | if (saving_output) |
155 | return; | |
8532893d | 156 | |
546b8ca7 SG |
157 | if (Tcl_DStringLength (&stdout_buffer) > 1000) |
158 | flush_holdbuf (); | |
8532893d SG |
159 | } |
160 | ||
754e5da2 SG |
161 | static int |
162 | gdbtk_query (args) | |
163 | va_list args; | |
164 | { | |
165 | char *query; | |
166 | char buf[200]; | |
167 | long val; | |
168 | ||
169 | query = va_arg (args, char *); | |
170 | ||
171 | vsprintf(buf, query, args); | |
172 | Tcl_VarEval (interp, "gdbtk_tcl_query ", "{", buf, "}", NULL); | |
173 | ||
174 | val = atol (interp->result); | |
175 | return val; | |
176 | } | |
177 | \f | |
754e5da2 SG |
178 | static void |
179 | breakpoint_notify(b, action) | |
180 | struct breakpoint *b; | |
181 | const char *action; | |
182 | { | |
183 | struct symbol *sym; | |
8532893d | 184 | char bpnum[50], line[50], pc[50]; |
754e5da2 SG |
185 | struct symtab_and_line sal; |
186 | char *filename; | |
187 | int v; | |
188 | ||
189 | if (b->type != bp_breakpoint) | |
190 | return; | |
191 | ||
192 | sal = find_pc_line (b->address, 0); | |
193 | ||
637b1661 | 194 | filename = symtab_to_filename (sal.symtab); |
754e5da2 SG |
195 | |
196 | sprintf (bpnum, "%d", b->number); | |
197 | sprintf (line, "%d", sal.line); | |
546b8ca7 | 198 | sprintf (pc, "0x%lx", b->address); |
754e5da2 SG |
199 | |
200 | v = Tcl_VarEval (interp, | |
201 | "gdbtk_tcl_breakpoint ", | |
202 | action, | |
203 | " ", bpnum, | |
204 | " ", filename, | |
205 | " ", line, | |
8532893d | 206 | " ", pc, |
754e5da2 SG |
207 | NULL); |
208 | ||
209 | if (v != TCL_OK) | |
210 | { | |
546b8ca7 SG |
211 | gdbtk_fputs (interp->result, gdb_stdout); |
212 | gdbtk_fputs ("\n", gdb_stdout); | |
754e5da2 | 213 | } |
754e5da2 SG |
214 | } |
215 | ||
216 | static void | |
217 | gdbtk_create_breakpoint(b) | |
218 | struct breakpoint *b; | |
219 | { | |
220 | breakpoint_notify(b, "create"); | |
221 | } | |
222 | ||
223 | static void | |
224 | gdbtk_delete_breakpoint(b) | |
225 | struct breakpoint *b; | |
226 | { | |
227 | breakpoint_notify(b, "delete"); | |
228 | } | |
229 | ||
230 | static void | |
231 | gdbtk_enable_breakpoint(b) | |
232 | struct breakpoint *b; | |
233 | { | |
234 | breakpoint_notify(b, "enable"); | |
235 | } | |
236 | ||
237 | static void | |
238 | gdbtk_disable_breakpoint(b) | |
239 | struct breakpoint *b; | |
240 | { | |
241 | breakpoint_notify(b, "disable"); | |
242 | } | |
243 | \f | |
244 | /* This implements the TCL command `gdb_loc', which returns a list consisting | |
245 | of the source and line number associated with the current pc. */ | |
246 | ||
247 | static int | |
248 | gdb_loc (clientData, interp, argc, argv) | |
249 | ClientData clientData; | |
250 | Tcl_Interp *interp; | |
251 | int argc; | |
252 | char *argv[]; | |
253 | { | |
254 | char *filename; | |
255 | char buf[100]; | |
256 | struct symtab_and_line sal; | |
257 | char *funcname; | |
8532893d | 258 | CORE_ADDR pc; |
754e5da2 SG |
259 | |
260 | if (argc == 1) | |
261 | { | |
1dfc8dfb | 262 | pc = selected_frame ? selected_frame->pc : stop_pc; |
754e5da2 SG |
263 | sal = find_pc_line (pc, 0); |
264 | } | |
265 | else if (argc == 2) | |
266 | { | |
754e5da2 | 267 | struct symtabs_and_lines sals; |
8532893d | 268 | int nelts; |
754e5da2 SG |
269 | |
270 | sals = decode_line_spec (argv[1], 1); | |
271 | ||
8532893d SG |
272 | nelts = sals.nelts; |
273 | sal = sals.sals[0]; | |
274 | free (sals.sals); | |
275 | ||
754e5da2 SG |
276 | if (sals.nelts != 1) |
277 | { | |
278 | Tcl_SetResult (interp, "Ambiguous line spec", TCL_STATIC); | |
754e5da2 SG |
279 | return TCL_ERROR; |
280 | } | |
281 | ||
8532893d | 282 | pc = sal.pc; |
754e5da2 SG |
283 | } |
284 | else | |
285 | { | |
286 | Tcl_SetResult (interp, "wrong # args", TCL_STATIC); | |
287 | return TCL_ERROR; | |
288 | } | |
289 | ||
754e5da2 SG |
290 | if (sal.symtab) |
291 | Tcl_AppendElement (interp, sal.symtab->filename); | |
292 | else | |
293 | Tcl_AppendElement (interp, ""); | |
8532893d SG |
294 | |
295 | find_pc_partial_function (pc, &funcname, NULL, NULL); | |
754e5da2 | 296 | Tcl_AppendElement (interp, funcname); |
8532893d | 297 | |
637b1661 | 298 | filename = symtab_to_filename (sal.symtab); |
754e5da2 | 299 | Tcl_AppendElement (interp, filename); |
8532893d SG |
300 | |
301 | sprintf (buf, "%d", sal.line); | |
754e5da2 SG |
302 | Tcl_AppendElement (interp, buf); /* line number */ |
303 | ||
546b8ca7 | 304 | sprintf (buf, "0x%lx", pc); |
8532893d SG |
305 | Tcl_AppendElement (interp, buf); /* PC */ |
306 | ||
754e5da2 SG |
307 | return TCL_OK; |
308 | } | |
309 | \f | |
5b21fb68 SG |
310 | /* This implements the TCL command `gdb_sourcelines', which returns a list of |
311 | all of the lines containing executable code for the specified source file | |
312 | (ie: lines where you can put breakpoints). */ | |
313 | ||
314 | static int | |
315 | gdb_sourcelines (clientData, interp, argc, argv) | |
316 | ClientData clientData; | |
317 | Tcl_Interp *interp; | |
318 | int argc; | |
319 | char *argv[]; | |
320 | { | |
321 | struct symtab *symtab; | |
322 | struct linetable_entry *le; | |
323 | int nlines; | |
324 | char buf[100]; | |
325 | ||
326 | if (argc != 2) | |
327 | { | |
328 | Tcl_SetResult (interp, "wrong # args", TCL_STATIC); | |
329 | return TCL_ERROR; | |
330 | } | |
331 | ||
332 | symtab = lookup_symtab (argv[1]); | |
333 | ||
334 | if (!symtab) | |
335 | { | |
336 | Tcl_SetResult (interp, "No such file", TCL_STATIC); | |
337 | return TCL_ERROR; | |
338 | } | |
339 | ||
340 | /* If there's no linetable, or no entries, then we are done. */ | |
341 | ||
342 | if (!symtab->linetable | |
343 | || symtab->linetable->nitems == 0) | |
344 | { | |
345 | Tcl_AppendElement (interp, ""); | |
346 | return TCL_OK; | |
347 | } | |
348 | ||
349 | le = symtab->linetable->item; | |
350 | nlines = symtab->linetable->nitems; | |
351 | ||
352 | for (;nlines > 0; nlines--, le++) | |
353 | { | |
354 | /* If the pc of this line is the same as the pc of the next line, then | |
355 | just skip it. */ | |
356 | if (nlines > 1 | |
357 | && le->pc == (le + 1)->pc) | |
358 | continue; | |
359 | ||
360 | sprintf (buf, "%d", le->line); | |
361 | Tcl_AppendElement (interp, buf); | |
362 | } | |
363 | ||
364 | return TCL_OK; | |
365 | } | |
366 | \f | |
746d1df4 SG |
367 | static int |
368 | map_arg_registers (argc, argv, func, argp) | |
369 | int argc; | |
370 | char *argv[]; | |
371 | int (*func) PARAMS ((int regnum, void *argp)); | |
372 | void *argp; | |
373 | { | |
374 | int regnum; | |
375 | ||
376 | /* Note that the test for a valid register must include checking the | |
377 | reg_names array because NUM_REGS may be allocated for the union of the | |
378 | register sets within a family of related processors. In this case, the | |
379 | trailing entries of reg_names will change depending upon the particular | |
380 | processor being debugged. */ | |
381 | ||
382 | if (argc == 0) /* No args, just do all the regs */ | |
383 | { | |
384 | for (regnum = 0; | |
385 | regnum < NUM_REGS | |
386 | && reg_names[regnum] != NULL | |
387 | && *reg_names[regnum] != '\000'; | |
388 | regnum++) | |
389 | func (regnum, argp); | |
390 | ||
391 | return TCL_OK; | |
392 | } | |
393 | ||
394 | /* Else, list of register #s, just do listed regs */ | |
395 | for (; argc > 0; argc--, argv++) | |
396 | { | |
397 | regnum = atoi (*argv); | |
398 | ||
399 | if (regnum >= 0 | |
400 | && regnum < NUM_REGS | |
401 | && reg_names[regnum] != NULL | |
402 | && *reg_names[regnum] != '\000') | |
403 | func (regnum, argp); | |
404 | else | |
405 | { | |
406 | Tcl_SetResult (interp, "bad register number", TCL_STATIC); | |
407 | ||
408 | return TCL_ERROR; | |
409 | } | |
410 | } | |
411 | ||
412 | return TCL_OK; | |
413 | } | |
414 | ||
415 | static int | |
416 | get_register_name (regnum, argp) | |
417 | int regnum; | |
418 | void *argp; /* Ignored */ | |
419 | { | |
420 | Tcl_AppendElement (interp, reg_names[regnum]); | |
421 | } | |
422 | ||
5b21fb68 SG |
423 | /* This implements the TCL command `gdb_regnames', which returns a list of |
424 | all of the register names. */ | |
425 | ||
426 | static int | |
427 | gdb_regnames (clientData, interp, argc, argv) | |
428 | ClientData clientData; | |
429 | Tcl_Interp *interp; | |
430 | int argc; | |
431 | char *argv[]; | |
432 | { | |
746d1df4 SG |
433 | argc--; |
434 | argv++; | |
435 | ||
436 | return map_arg_registers (argc, argv, get_register_name, 0); | |
437 | } | |
438 | ||
746d1df4 SG |
439 | #ifndef REGISTER_CONVERTIBLE |
440 | #define REGISTER_CONVERTIBLE(x) (0 != 0) | |
441 | #endif | |
442 | ||
443 | #ifndef REGISTER_CONVERT_TO_VIRTUAL | |
444 | #define REGISTER_CONVERT_TO_VIRTUAL(x, y, z, a) | |
445 | #endif | |
446 | ||
447 | #ifndef INVALID_FLOAT | |
448 | #define INVALID_FLOAT(x, y) (0 != 0) | |
449 | #endif | |
450 | ||
451 | static int | |
452 | get_register (regnum, fp) | |
453 | void *fp; | |
454 | { | |
455 | char raw_buffer[MAX_REGISTER_RAW_SIZE]; | |
456 | char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; | |
457 | int format = (int)fp; | |
458 | ||
459 | if (read_relative_register_raw_bytes (regnum, raw_buffer)) | |
460 | { | |
461 | Tcl_AppendElement (interp, "Optimized out"); | |
462 | return; | |
463 | } | |
464 | ||
86db943c | 465 | start_saving_output (); /* Start collecting stdout */ |
746d1df4 SG |
466 | |
467 | /* Convert raw data to virtual format if necessary. */ | |
468 | ||
469 | if (REGISTER_CONVERTIBLE (regnum)) | |
470 | { | |
471 | REGISTER_CONVERT_TO_VIRTUAL (regnum, REGISTER_VIRTUAL_TYPE (regnum), | |
472 | raw_buffer, virtual_buffer); | |
473 | } | |
474 | else | |
475 | memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum)); | |
476 | ||
477 | val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_buffer, 0, | |
478 | gdb_stdout, format, 1, 0, Val_pretty_default); | |
479 | ||
86db943c | 480 | Tcl_AppendElement (interp, get_saved_output ()); |
746d1df4 | 481 | |
86db943c | 482 | finish_saving_output (); /* Set stdout back to normal */ |
746d1df4 SG |
483 | } |
484 | ||
485 | static int | |
486 | gdb_fetch_registers (clientData, interp, argc, argv) | |
487 | ClientData clientData; | |
488 | Tcl_Interp *interp; | |
489 | int argc; | |
490 | char *argv[]; | |
491 | { | |
492 | int format; | |
493 | ||
494 | if (argc < 2) | |
5b21fb68 SG |
495 | { |
496 | Tcl_SetResult (interp, "wrong # args", TCL_STATIC); | |
497 | return TCL_ERROR; | |
498 | } | |
499 | ||
746d1df4 SG |
500 | argc--; |
501 | argv++; | |
5b21fb68 | 502 | |
746d1df4 SG |
503 | argc--; |
504 | format = **argv++; | |
505 | ||
506 | return map_arg_registers (argc, argv, get_register, format); | |
507 | } | |
508 | ||
509 | /* This contains the previous values of the registers, since the last call to | |
510 | gdb_changed_register_list. */ | |
511 | ||
512 | static char old_regs[REGISTER_BYTES]; | |
513 | ||
514 | static int | |
515 | register_changed_p (regnum, argp) | |
516 | void *argp; /* Ignored */ | |
517 | { | |
518 | char raw_buffer[MAX_REGISTER_RAW_SIZE]; | |
519 | char buf[100]; | |
520 | ||
521 | if (read_relative_register_raw_bytes (regnum, raw_buffer)) | |
522 | return; | |
523 | ||
524 | if (memcmp (&old_regs[REGISTER_BYTE (regnum)], raw_buffer, | |
525 | REGISTER_RAW_SIZE (regnum)) == 0) | |
526 | return; | |
527 | ||
528 | /* Found a changed register. Save new value and return it's number. */ | |
529 | ||
530 | memcpy (&old_regs[REGISTER_BYTE (regnum)], raw_buffer, | |
531 | REGISTER_RAW_SIZE (regnum)); | |
532 | ||
533 | sprintf (buf, "%d", regnum); | |
534 | Tcl_AppendElement (interp, buf); | |
535 | } | |
536 | ||
537 | static int | |
538 | gdb_changed_register_list (clientData, interp, argc, argv) | |
539 | ClientData clientData; | |
540 | Tcl_Interp *interp; | |
541 | int argc; | |
542 | char *argv[]; | |
543 | { | |
544 | int format; | |
545 | ||
546 | argc--; | |
547 | argv++; | |
548 | ||
549 | return map_arg_registers (argc, argv, register_changed_p, NULL); | |
5b21fb68 SG |
550 | } |
551 | \f | |
754e5da2 SG |
552 | /* This implements the TCL command `gdb_cmd', which sends it's argument into |
553 | the GDB command scanner. */ | |
554 | ||
555 | static int | |
556 | gdb_cmd (clientData, interp, argc, argv) | |
557 | ClientData clientData; | |
558 | Tcl_Interp *interp; | |
559 | int argc; | |
560 | char *argv[]; | |
561 | { | |
754e5da2 SG |
562 | if (argc != 2) |
563 | { | |
564 | Tcl_SetResult (interp, "wrong # args", TCL_STATIC); | |
565 | return TCL_ERROR; | |
566 | } | |
567 | ||
86db943c | 568 | execute_command (argv[1], 1); |
479f0f18 | 569 | |
754e5da2 | 570 | bpstat_do_actions (&stop_bpstat); |
754e5da2 | 571 | |
8532893d SG |
572 | /* Drain all buffered command output */ |
573 | ||
8532893d SG |
574 | gdb_flush (gdb_stdout); |
575 | ||
754e5da2 SG |
576 | return TCL_OK; |
577 | } | |
578 | ||
86db943c SG |
579 | /* This routine acts as a top-level for all GDB code called by tcl/Tk. It |
580 | handles cleanups, and calls to return_to_top_level (usually via error). | |
581 | This is necessary in order to prevent a longjmp out of the bowels of Tk, | |
582 | possibly leaving things in a bad state. Since this routine can be called | |
583 | recursively, it needs to save and restore the contents of the jmp_buf as | |
584 | necessary. */ | |
585 | ||
586 | static int | |
587 | call_wrapper (clientData, interp, argc, argv) | |
588 | ClientData clientData; | |
589 | Tcl_Interp *interp; | |
590 | int argc; | |
591 | char *argv[]; | |
592 | { | |
593 | int val; | |
594 | struct cleanup *saved_cleanup_chain; | |
595 | Tcl_CmdProc *func; | |
596 | jmp_buf saved_error_return; | |
597 | ||
598 | func = (Tcl_CmdProc *)clientData; | |
599 | memcpy (saved_error_return, error_return, sizeof (jmp_buf)); | |
600 | ||
601 | saved_cleanup_chain = save_cleanups (); | |
602 | ||
603 | if (!setjmp (error_return)) | |
604 | val = func (clientData, interp, argc, argv); | |
605 | else | |
606 | { | |
607 | val = TCL_ERROR; /* Flag an error for TCL */ | |
608 | ||
609 | finish_saving_output (); /* Restore stdout to normal */ | |
610 | ||
611 | gdb_flush (gdb_stderr); /* Flush error output */ | |
612 | ||
613 | /* In case of an error, we may need to force the GUI into idle mode because | |
614 | gdbtk_call_command may have bombed out while in the command routine. */ | |
615 | ||
616 | Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL); | |
617 | } | |
618 | ||
619 | do_cleanups (ALL_CLEANUPS); | |
620 | ||
621 | restore_cleanups (saved_cleanup_chain); | |
622 | ||
623 | memcpy (error_return, saved_error_return, sizeof (jmp_buf)); | |
624 | ||
625 | return val; | |
626 | } | |
627 | ||
754e5da2 SG |
628 | static int |
629 | gdb_listfiles (clientData, interp, argc, argv) | |
630 | ClientData clientData; | |
631 | Tcl_Interp *interp; | |
632 | int argc; | |
633 | char *argv[]; | |
634 | { | |
635 | int val; | |
636 | struct objfile *objfile; | |
637 | struct partial_symtab *psymtab; | |
546b8ca7 | 638 | struct symtab *symtab; |
754e5da2 SG |
639 | |
640 | ALL_PSYMTABS (objfile, psymtab) | |
641 | Tcl_AppendElement (interp, psymtab->filename); | |
642 | ||
546b8ca7 SG |
643 | ALL_SYMTABS (objfile, symtab) |
644 | Tcl_AppendElement (interp, symtab->filename); | |
645 | ||
754e5da2 SG |
646 | return TCL_OK; |
647 | } | |
479f0f18 SG |
648 | |
649 | static int | |
650 | gdb_stop (clientData, interp, argc, argv) | |
651 | ClientData clientData; | |
652 | Tcl_Interp *interp; | |
653 | int argc; | |
654 | char *argv[]; | |
655 | { | |
6c27841f | 656 | target_stop (); |
546b8ca7 SG |
657 | |
658 | return TCL_OK; | |
479f0f18 SG |
659 | } |
660 | ||
754e5da2 SG |
661 | \f |
662 | static void | |
663 | tk_command (cmd, from_tty) | |
664 | char *cmd; | |
665 | int from_tty; | |
666 | { | |
546b8ca7 SG |
667 | int retval; |
668 | char *result; | |
669 | struct cleanup *old_chain; | |
670 | ||
671 | retval = Tcl_Eval (interp, cmd); | |
672 | ||
673 | result = strdup (interp->result); | |
754e5da2 | 674 | |
546b8ca7 SG |
675 | old_chain = make_cleanup (free, result); |
676 | ||
677 | if (retval != TCL_OK) | |
678 | error (result); | |
679 | ||
680 | printf_unfiltered ("%s\n", result); | |
681 | ||
682 | do_cleanups (old_chain); | |
754e5da2 SG |
683 | } |
684 | ||
685 | static void | |
686 | cleanup_init (ignored) | |
687 | int ignored; | |
688 | { | |
689 | if (mainWindow != NULL) | |
690 | Tk_DestroyWindow (mainWindow); | |
691 | mainWindow = NULL; | |
692 | ||
693 | if (interp != NULL) | |
694 | Tcl_DeleteInterp (interp); | |
695 | interp = NULL; | |
696 | } | |
697 | ||
637b1661 SG |
698 | /* Come here during long calculations to check for GUI events. Usually invoked |
699 | via the QUIT macro. */ | |
700 | ||
701 | static void | |
702 | gdbtk_interactive () | |
703 | { | |
704 | /* Tk_DoOneEvent (TK_DONT_WAIT|TK_IDLE_EVENTS); */ | |
705 | } | |
706 | ||
479f0f18 SG |
707 | /* Come here when there is activity on the X file descriptor. */ |
708 | ||
709 | static void | |
710 | x_event (signo) | |
711 | int signo; | |
712 | { | |
713 | /* Process pending events */ | |
714 | ||
715 | while (Tk_DoOneEvent (TK_DONT_WAIT|TK_ALL_EVENTS) != 0); | |
716 | } | |
717 | ||
718 | static int | |
719 | gdbtk_wait (pid, ourstatus) | |
720 | int pid; | |
721 | struct target_waitstatus *ourstatus; | |
722 | { | |
736a82e7 SG |
723 | struct sigaction action; |
724 | static sigset_t nullsigmask = {0}; | |
725 | ||
726 | #ifndef SA_RESTART | |
727 | /* Needed for SunOS 4.1.x */ | |
728 | #define SA_RESTART 0 | |
546b8ca7 | 729 | #endif |
479f0f18 | 730 | |
736a82e7 SG |
731 | action.sa_handler = x_event; |
732 | action.sa_mask = nullsigmask; | |
733 | action.sa_flags = SA_RESTART; | |
734 | sigaction(SIGIO, &action, NULL); | |
735 | ||
479f0f18 SG |
736 | pid = target_wait (pid, ourstatus); |
737 | ||
736a82e7 SG |
738 | action.sa_handler = SIG_IGN; |
739 | sigaction(SIGIO, &action, NULL); | |
479f0f18 SG |
740 | |
741 | return pid; | |
742 | } | |
743 | ||
744 | /* This is called from execute_command, and provides a wrapper around | |
745 | various command routines in a place where both protocol messages and | |
746 | user input both flow through. Mostly this is used for indicating whether | |
747 | the target process is running or not. | |
748 | */ | |
749 | ||
750 | static void | |
751 | gdbtk_call_command (cmdblk, arg, from_tty) | |
752 | struct cmd_list_element *cmdblk; | |
753 | char *arg; | |
754 | int from_tty; | |
755 | { | |
756 | if (cmdblk->class == class_run) | |
757 | { | |
758 | Tcl_VarEval (interp, "gdbtk_tcl_busy", NULL); | |
759 | (*cmdblk->function.cfunc)(arg, from_tty); | |
760 | Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL); | |
761 | } | |
762 | else | |
763 | (*cmdblk->function.cfunc)(arg, from_tty); | |
764 | } | |
765 | ||
754e5da2 SG |
766 | static void |
767 | gdbtk_init () | |
768 | { | |
769 | struct cleanup *old_chain; | |
770 | char *gdbtk_filename; | |
479f0f18 | 771 | int i; |
736a82e7 SG |
772 | struct sigaction action; |
773 | static sigset_t nullsigmask = {0}; | |
754e5da2 SG |
774 | |
775 | old_chain = make_cleanup (cleanup_init, 0); | |
776 | ||
777 | /* First init tcl and tk. */ | |
778 | ||
779 | interp = Tcl_CreateInterp (); | |
780 | ||
781 | if (!interp) | |
782 | error ("Tcl_CreateInterp failed"); | |
783 | ||
546b8ca7 SG |
784 | Tcl_DStringInit (&stdout_buffer); /* Setup stdout buffer */ |
785 | ||
754e5da2 SG |
786 | mainWindow = Tk_CreateMainWindow (interp, NULL, "gdb", "Gdb"); |
787 | ||
788 | if (!mainWindow) | |
789 | return; /* DISPLAY probably not set */ | |
790 | ||
791 | if (Tcl_Init(interp) != TCL_OK) | |
792 | error ("Tcl_Init failed: %s", interp->result); | |
793 | ||
794 | if (Tk_Init(interp) != TCL_OK) | |
795 | error ("Tk_Init failed: %s", interp->result); | |
796 | ||
86db943c SG |
797 | Tcl_CreateCommand (interp, "gdb_cmd", call_wrapper, gdb_cmd, NULL); |
798 | Tcl_CreateCommand (interp, "gdb_loc", call_wrapper, gdb_loc, NULL); | |
799 | Tcl_CreateCommand (interp, "gdb_sourcelines", call_wrapper, gdb_sourcelines, | |
800 | NULL); | |
801 | Tcl_CreateCommand (interp, "gdb_listfiles", call_wrapper, gdb_listfiles, | |
746d1df4 | 802 | NULL); |
86db943c SG |
803 | Tcl_CreateCommand (interp, "gdb_stop", call_wrapper, gdb_stop, NULL); |
804 | Tcl_CreateCommand (interp, "gdb_regnames", call_wrapper, gdb_regnames, NULL); | |
805 | Tcl_CreateCommand (interp, "gdb_fetch_registers", call_wrapper, | |
806 | gdb_fetch_registers, NULL); | |
807 | Tcl_CreateCommand (interp, "gdb_changed_register_list", call_wrapper, | |
808 | gdb_changed_register_list, NULL); | |
754e5da2 SG |
809 | |
810 | gdbtk_filename = getenv ("GDBTK_FILENAME"); | |
8532893d SG |
811 | if (!gdbtk_filename) |
812 | if (access ("gdbtk.tcl", R_OK) == 0) | |
813 | gdbtk_filename = "gdbtk.tcl"; | |
814 | else | |
815 | gdbtk_filename = GDBTK_FILENAME; | |
816 | ||
817 | if (Tcl_EvalFile (interp, gdbtk_filename) != TCL_OK) | |
818 | error ("Failure reading %s: %s", gdbtk_filename, interp->result); | |
754e5da2 | 819 | |
cd2df226 | 820 | /* Get the file descriptor for the X server */ |
479f0f18 | 821 | |
cd2df226 | 822 | x_fd = ConnectionNumber (Tk_Display (mainWindow)); |
479f0f18 SG |
823 | |
824 | /* Setup for I/O interrupts */ | |
825 | ||
736a82e7 SG |
826 | action.sa_mask = nullsigmask; |
827 | action.sa_flags = 0; | |
828 | action.sa_handler = SIG_IGN; | |
829 | sigaction(SIGIO, &action, NULL); | |
830 | ||
831 | #ifdef FIOASYNC | |
832 | i = 1; | |
833 | if (ioctl (x_fd, FIOASYNC, &i)) | |
834 | perror_with_name ("gdbtk_init: ioctl FIOASYNC failed"); | |
479f0f18 | 835 | |
736a82e7 SG |
836 | i = getpid(); |
837 | if (ioctl (x_fd, SIOCSPGRP, &i)) | |
838 | perror_with_name ("gdbtk_init: ioctl SIOCSPGRP failed"); | |
546b8ca7 SG |
839 | #else |
840 | if (ioctl (x_fd, I_SETSIG, S_INPUT|S_RDNORM) < 0) | |
736a82e7 SG |
841 | perror_with_name ("gdbtk_init: ioctl I_SETSIG failed"); |
842 | #endif /* ifndef FIOASYNC */ | |
479f0f18 | 843 | |
754e5da2 SG |
844 | command_loop_hook = Tk_MainLoop; |
845 | fputs_unfiltered_hook = gdbtk_fputs; | |
846 | print_frame_info_listing_hook = null_routine; | |
847 | query_hook = gdbtk_query; | |
848 | flush_hook = gdbtk_flush; | |
849 | create_breakpoint_hook = gdbtk_create_breakpoint; | |
850 | delete_breakpoint_hook = gdbtk_delete_breakpoint; | |
851 | enable_breakpoint_hook = gdbtk_enable_breakpoint; | |
852 | disable_breakpoint_hook = gdbtk_disable_breakpoint; | |
637b1661 | 853 | interactive_hook = gdbtk_interactive; |
479f0f18 SG |
854 | target_wait_hook = gdbtk_wait; |
855 | call_command_hook = gdbtk_call_command; | |
754e5da2 SG |
856 | |
857 | discard_cleanups (old_chain); | |
858 | ||
859 | add_com ("tk", class_obscure, tk_command, | |
860 | "Send a command directly into tk."); | |
861 | } | |
862 | ||
863 | /* Come here during initialze_all_files () */ | |
864 | ||
865 | void | |
866 | _initialize_gdbtk () | |
867 | { | |
c5197511 SG |
868 | if (use_windows) |
869 | { | |
870 | /* Tell the rest of the world that Gdbtk is now set up. */ | |
754e5da2 | 871 | |
c5197511 SG |
872 | init_ui_hook = gdbtk_init; |
873 | } | |
754e5da2 | 874 | } |