* expression.h (OP_LABELED): New operator, for Chill
[deliverable/binutils-gdb.git] / gdb / gdbtk.c
1 /* Tcl/Tk interface routines.
2 Copyright 1994, 1995 Free Software Foundation, Inc.
3
4 Written by Stu Grossman <grossman@cygnus.com> of Cygnus Support.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 #include "defs.h"
23 #include "symtab.h"
24 #include "inferior.h"
25 #include "command.h"
26 #include "bfd.h"
27 #include "symfile.h"
28 #include "objfiles.h"
29 #include "target.h"
30 #include <tcl.h>
31 #include <tk.h>
32 #include <varargs.h>
33 #include <signal.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <setjmp.h>
37 #include "top.h"
38 #include <sys/ioctl.h>
39 #include <string.h>
40 #include "dis-asm.h"
41
42 #ifndef FIOASYNC
43 #include <sys/stropts.h>
44 #endif
45
46 /* Non-zero means that we're doing the gdbtk interface. */
47 int gdbtk = 0;
48
49 /* Non-zero means we are reloading breakpoints, etc from the
50 Gdbtk kernel, and we should suppress various messages */
51 static int gdbtk_reloading = 0;
52
53 /* Handle for TCL interpreter */
54 static Tcl_Interp *interp = NULL;
55
56 /* Handle for TK main window */
57 static Tk_Window mainWindow = NULL;
58
59 static int x_fd; /* X network socket */
60
61 /* This variable determines where memory used for disassembly is read from.
62
63 If > 0, then disassembly comes from the exec file rather than the target
64 (which might be at the other end of a slow serial link). If == 0 then
65 disassembly comes from target. If < 0 disassembly is automatically switched
66 to the target if it's an inferior process, otherwise the exec file is
67 used.
68 */
69
70 static int disassemble_from_exec = -1;
71
72 static void
73 null_routine(arg)
74 int arg;
75 {
76 }
77
78 /* The following routines deal with stdout/stderr data, which is created by
79 {f}printf_{un}filtered and friends. gdbtk_fputs and gdbtk_flush are the
80 lowest level of these routines and capture all output from the rest of GDB.
81 Normally they present their data to tcl via callbacks to the following tcl
82 routines: gdbtk_tcl_fputs, gdbtk_tcl_fputs_error, and gdbtk_flush. These
83 in turn call tk routines to update the display.
84
85 Under some circumstances, you may want to collect the output so that it can
86 be returned as the value of a tcl procedure. This can be done by
87 surrounding the output routines with calls to start_saving_output and
88 finish_saving_output. The saved data can then be retrieved with
89 get_saved_output (but this must be done before the call to
90 finish_saving_output). */
91
92 /* Dynamic string header for stdout. */
93
94 static Tcl_DString stdout_buffer;
95
96 /* Use this to collect stdout output that will be returned as the result of a
97 tcl command. */
98
99 static int saving_output = 0;
100
101 static void
102 start_saving_output ()
103 {
104 saving_output = 1;
105 }
106
107 #define get_saved_output() (Tcl_DStringValue (&stdout_buffer))
108
109 static void
110 finish_saving_output ()
111 {
112 if (!saving_output)
113 return;
114
115 saving_output = 0;
116
117 Tcl_DStringFree (&stdout_buffer);
118 }
119 \f
120 /* This routine redirects the output of fputs_unfiltered so that
121 the user can see what's going on in his debugger window. */
122
123 static void
124 flush_holdbuf ()
125 {
126 char *s, *argv[1];
127
128 /* We use Tcl_Merge to quote braces and funny characters as necessary. */
129
130 argv[0] = Tcl_DStringValue (&stdout_buffer);
131 s = Tcl_Merge (1, argv);
132
133 Tcl_DStringFree (&stdout_buffer);
134
135 Tcl_VarEval (interp, "gdbtk_tcl_fputs ", s, NULL);
136
137 free (s);
138 }
139
140 static void
141 gdbtk_flush (stream)
142 FILE *stream;
143 {
144 if (stream != gdb_stdout || saving_output)
145 return;
146
147 /* Flush output from C to tcl land. */
148
149 flush_holdbuf ();
150
151 /* Force immediate screen update */
152
153 Tcl_VarEval (interp, "gdbtk_tcl_flush", NULL);
154 }
155
156 static void
157 gdbtk_fputs (ptr, stream)
158 const char *ptr;
159 FILE *stream;
160 {
161 int len;
162
163 if (stream != gdb_stdout)
164 {
165 Tcl_VarEval (interp, "gdbtk_tcl_fputs_error ", "{", ptr, "}", NULL);
166 return;
167 }
168
169 Tcl_DStringAppend (&stdout_buffer, ptr, -1);
170
171 if (saving_output)
172 return;
173
174 if (Tcl_DStringLength (&stdout_buffer) > 1000)
175 flush_holdbuf ();
176 }
177
178 static int
179 gdbtk_query (args)
180 va_list args;
181 {
182 char *query;
183 char buf[200];
184 long val;
185
186 query = va_arg (args, char *);
187
188 vsprintf(buf, query, args);
189 Tcl_VarEval (interp, "gdbtk_tcl_query ", "{", buf, "}", NULL);
190
191 val = atol (interp->result);
192 return val;
193 }
194 \f
195 static void
196 breakpoint_notify(b, action)
197 struct breakpoint *b;
198 const char *action;
199 {
200 struct symbol *sym;
201 char bpnum[50], line[50], pc[50];
202 struct symtab_and_line sal;
203 char *filename;
204 int v;
205
206 if (b->type != bp_breakpoint)
207 return;
208
209 sal = find_pc_line (b->address, 0);
210
211 filename = symtab_to_filename (sal.symtab);
212
213 sprintf (bpnum, "%d", b->number);
214 sprintf (line, "%d", sal.line);
215 sprintf (pc, "0x%lx", b->address);
216
217 v = Tcl_VarEval (interp,
218 "gdbtk_tcl_breakpoint ",
219 action,
220 " ", bpnum,
221 " ", filename ? filename : "{}",
222 " ", line,
223 " ", pc,
224 NULL);
225
226 if (v != TCL_OK)
227 {
228 gdbtk_fputs (interp->result, gdb_stdout);
229 gdbtk_fputs ("\n", gdb_stdout);
230 }
231 }
232
233 static void
234 gdbtk_create_breakpoint(b)
235 struct breakpoint *b;
236 {
237 breakpoint_notify(b, "create");
238 }
239
240 static void
241 gdbtk_delete_breakpoint(b)
242 struct breakpoint *b;
243 {
244 breakpoint_notify(b, "delete");
245 }
246
247 static void
248 gdbtk_enable_breakpoint(b)
249 struct breakpoint *b;
250 {
251 breakpoint_notify(b, "enable");
252 }
253
254 static void
255 gdbtk_disable_breakpoint(b)
256 struct breakpoint *b;
257 {
258 breakpoint_notify(b, "disable");
259 }
260 \f
261 /* This implements the TCL command `gdb_loc', which returns a list consisting
262 of the source and line number associated with the current pc. */
263
264 static int
265 gdb_loc (clientData, interp, argc, argv)
266 ClientData clientData;
267 Tcl_Interp *interp;
268 int argc;
269 char *argv[];
270 {
271 char *filename;
272 char buf[100];
273 struct symtab_and_line sal;
274 char *funcname;
275 CORE_ADDR pc;
276
277 if (argc == 1)
278 {
279 pc = selected_frame ? selected_frame->pc : stop_pc;
280 sal = find_pc_line (pc, 0);
281 }
282 else if (argc == 2)
283 {
284 struct symtabs_and_lines sals;
285 int nelts;
286
287 sals = decode_line_spec (argv[1], 1);
288
289 nelts = sals.nelts;
290 sal = sals.sals[0];
291 free (sals.sals);
292
293 if (sals.nelts != 1)
294 {
295 Tcl_SetResult (interp, "Ambiguous line spec", TCL_STATIC);
296 return TCL_ERROR;
297 }
298
299 pc = sal.pc;
300 }
301 else
302 {
303 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
304 return TCL_ERROR;
305 }
306
307 if (sal.symtab)
308 Tcl_AppendElement (interp, sal.symtab->filename);
309 else
310 Tcl_AppendElement (interp, "");
311
312 find_pc_partial_function (pc, &funcname, NULL, NULL);
313 Tcl_AppendElement (interp, funcname);
314
315 filename = symtab_to_filename (sal.symtab);
316 Tcl_AppendElement (interp, filename);
317
318 sprintf (buf, "%d", sal.line);
319 Tcl_AppendElement (interp, buf); /* line number */
320
321 sprintf (buf, "0x%lx", pc);
322 Tcl_AppendElement (interp, buf); /* PC */
323
324 return TCL_OK;
325 }
326 \f
327 /* This implements the TCL command `gdb_eval'. */
328
329 static int
330 gdb_eval (clientData, interp, argc, argv)
331 ClientData clientData;
332 Tcl_Interp *interp;
333 int argc;
334 char *argv[];
335 {
336 struct expression *expr;
337 struct cleanup *old_chain;
338 value_ptr val;
339
340 if (argc != 2)
341 {
342 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
343 return TCL_ERROR;
344 }
345
346 expr = parse_expression (argv[1]);
347
348 old_chain = make_cleanup (free_current_contents, &expr);
349
350 val = evaluate_expression (expr);
351
352 start_saving_output (); /* Start collecting stdout */
353
354 val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), VALUE_ADDRESS (val),
355 gdb_stdout, 0, 0, 0, 0);
356 #if 0
357 value_print (val, gdb_stdout, 0, 0);
358 #endif
359
360 Tcl_AppendElement (interp, get_saved_output ());
361
362 finish_saving_output (); /* Set stdout back to normal */
363
364 do_cleanups (old_chain);
365
366 return TCL_OK;
367 }
368 \f
369 /* This implements the TCL command `gdb_sourcelines', which returns a list of
370 all of the lines containing executable code for the specified source file
371 (ie: lines where you can put breakpoints). */
372
373 static int
374 gdb_sourcelines (clientData, interp, argc, argv)
375 ClientData clientData;
376 Tcl_Interp *interp;
377 int argc;
378 char *argv[];
379 {
380 struct symtab *symtab;
381 struct linetable_entry *le;
382 int nlines;
383 char buf[100];
384
385 if (argc != 2)
386 {
387 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
388 return TCL_ERROR;
389 }
390
391 symtab = lookup_symtab (argv[1]);
392
393 if (!symtab)
394 {
395 Tcl_SetResult (interp, "No such file", TCL_STATIC);
396 return TCL_ERROR;
397 }
398
399 /* If there's no linetable, or no entries, then we are done. */
400
401 if (!symtab->linetable
402 || symtab->linetable->nitems == 0)
403 {
404 Tcl_AppendElement (interp, "");
405 return TCL_OK;
406 }
407
408 le = symtab->linetable->item;
409 nlines = symtab->linetable->nitems;
410
411 for (;nlines > 0; nlines--, le++)
412 {
413 /* If the pc of this line is the same as the pc of the next line, then
414 just skip it. */
415 if (nlines > 1
416 && le->pc == (le + 1)->pc)
417 continue;
418
419 sprintf (buf, "%d", le->line);
420 Tcl_AppendElement (interp, buf);
421 }
422
423 return TCL_OK;
424 }
425 \f
426 static int
427 map_arg_registers (argc, argv, func, argp)
428 int argc;
429 char *argv[];
430 int (*func) PARAMS ((int regnum, void *argp));
431 void *argp;
432 {
433 int regnum;
434
435 /* Note that the test for a valid register must include checking the
436 reg_names array because NUM_REGS may be allocated for the union of the
437 register sets within a family of related processors. In this case, the
438 trailing entries of reg_names will change depending upon the particular
439 processor being debugged. */
440
441 if (argc == 0) /* No args, just do all the regs */
442 {
443 for (regnum = 0;
444 regnum < NUM_REGS
445 && reg_names[regnum] != NULL
446 && *reg_names[regnum] != '\000';
447 regnum++)
448 func (regnum, argp);
449
450 return TCL_OK;
451 }
452
453 /* Else, list of register #s, just do listed regs */
454 for (; argc > 0; argc--, argv++)
455 {
456 regnum = atoi (*argv);
457
458 if (regnum >= 0
459 && regnum < NUM_REGS
460 && reg_names[regnum] != NULL
461 && *reg_names[regnum] != '\000')
462 func (regnum, argp);
463 else
464 {
465 Tcl_SetResult (interp, "bad register number", TCL_STATIC);
466
467 return TCL_ERROR;
468 }
469 }
470
471 return TCL_OK;
472 }
473
474 static int
475 get_register_name (regnum, argp)
476 int regnum;
477 void *argp; /* Ignored */
478 {
479 Tcl_AppendElement (interp, reg_names[regnum]);
480 }
481
482 /* This implements the TCL command `gdb_regnames', which returns a list of
483 all of the register names. */
484
485 static int
486 gdb_regnames (clientData, interp, argc, argv)
487 ClientData clientData;
488 Tcl_Interp *interp;
489 int argc;
490 char *argv[];
491 {
492 argc--;
493 argv++;
494
495 return map_arg_registers (argc, argv, get_register_name, 0);
496 }
497
498 #ifndef REGISTER_CONVERTIBLE
499 #define REGISTER_CONVERTIBLE(x) (0 != 0)
500 #endif
501
502 #ifndef REGISTER_CONVERT_TO_VIRTUAL
503 #define REGISTER_CONVERT_TO_VIRTUAL(x, y, z, a)
504 #endif
505
506 #ifndef INVALID_FLOAT
507 #define INVALID_FLOAT(x, y) (0 != 0)
508 #endif
509
510 static int
511 get_register (regnum, fp)
512 void *fp;
513 {
514 char raw_buffer[MAX_REGISTER_RAW_SIZE];
515 char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
516 int format = (int)fp;
517
518 if (read_relative_register_raw_bytes (regnum, raw_buffer))
519 {
520 Tcl_AppendElement (interp, "Optimized out");
521 return;
522 }
523
524 start_saving_output (); /* Start collecting stdout */
525
526 /* Convert raw data to virtual format if necessary. */
527
528 if (REGISTER_CONVERTIBLE (regnum))
529 {
530 REGISTER_CONVERT_TO_VIRTUAL (regnum, REGISTER_VIRTUAL_TYPE (regnum),
531 raw_buffer, virtual_buffer);
532 }
533 else
534 memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
535
536 val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_buffer, 0,
537 gdb_stdout, format, 1, 0, Val_pretty_default);
538
539 Tcl_AppendElement (interp, get_saved_output ());
540
541 finish_saving_output (); /* Set stdout back to normal */
542 }
543
544 static int
545 gdb_fetch_registers (clientData, interp, argc, argv)
546 ClientData clientData;
547 Tcl_Interp *interp;
548 int argc;
549 char *argv[];
550 {
551 int format;
552
553 if (argc < 2)
554 {
555 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
556 return TCL_ERROR;
557 }
558
559 argc--;
560 argv++;
561
562 argc--;
563 format = **argv++;
564
565 return map_arg_registers (argc, argv, get_register, format);
566 }
567
568 /* This contains the previous values of the registers, since the last call to
569 gdb_changed_register_list. */
570
571 static char old_regs[REGISTER_BYTES];
572
573 static int
574 register_changed_p (regnum, argp)
575 void *argp; /* Ignored */
576 {
577 char raw_buffer[MAX_REGISTER_RAW_SIZE];
578 char buf[100];
579
580 if (read_relative_register_raw_bytes (regnum, raw_buffer))
581 return;
582
583 if (memcmp (&old_regs[REGISTER_BYTE (regnum)], raw_buffer,
584 REGISTER_RAW_SIZE (regnum)) == 0)
585 return;
586
587 /* Found a changed register. Save new value and return it's number. */
588
589 memcpy (&old_regs[REGISTER_BYTE (regnum)], raw_buffer,
590 REGISTER_RAW_SIZE (regnum));
591
592 sprintf (buf, "%d", regnum);
593 Tcl_AppendElement (interp, buf);
594 }
595
596 static int
597 gdb_changed_register_list (clientData, interp, argc, argv)
598 ClientData clientData;
599 Tcl_Interp *interp;
600 int argc;
601 char *argv[];
602 {
603 int format;
604
605 argc--;
606 argv++;
607
608 return map_arg_registers (argc, argv, register_changed_p, NULL);
609 }
610 \f
611 /* This implements the TCL command `gdb_cmd', which sends it's argument into
612 the GDB command scanner. */
613
614 static int
615 gdb_cmd (clientData, interp, argc, argv)
616 ClientData clientData;
617 Tcl_Interp *interp;
618 int argc;
619 char *argv[];
620 {
621 if (argc != 2)
622 {
623 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
624 return TCL_ERROR;
625 }
626
627 execute_command (argv[1], 1);
628
629 bpstat_do_actions (&stop_bpstat);
630
631 /* Drain all buffered command output */
632
633 gdb_flush (gdb_stdout);
634
635 return TCL_OK;
636 }
637
638 /* This routine acts as a top-level for all GDB code called by tcl/Tk. It
639 handles cleanups, and calls to return_to_top_level (usually via error).
640 This is necessary in order to prevent a longjmp out of the bowels of Tk,
641 possibly leaving things in a bad state. Since this routine can be called
642 recursively, it needs to save and restore the contents of the jmp_buf as
643 necessary. */
644
645 static int
646 call_wrapper (clientData, interp, argc, argv)
647 ClientData clientData;
648 Tcl_Interp *interp;
649 int argc;
650 char *argv[];
651 {
652 int val;
653 struct cleanup *saved_cleanup_chain;
654 Tcl_CmdProc *func;
655 jmp_buf saved_error_return;
656
657 func = (Tcl_CmdProc *)clientData;
658 memcpy (saved_error_return, error_return, sizeof (jmp_buf));
659
660 saved_cleanup_chain = save_cleanups ();
661
662 if (!setjmp (error_return))
663 val = func (clientData, interp, argc, argv);
664 else
665 {
666 val = TCL_ERROR; /* Flag an error for TCL */
667
668 finish_saving_output (); /* Restore stdout to normal */
669
670 dis_asm_read_memory_hook = 0; /* Restore disassembly hook */
671
672 gdb_flush (gdb_stderr); /* Flush error output */
673
674 gdb_flush (gdb_stdout); /* Sometimes error output comes here as well */
675
676 /* In case of an error, we may need to force the GUI into idle mode because
677 gdbtk_call_command may have bombed out while in the command routine. */
678
679 Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL);
680 }
681
682 do_cleanups (ALL_CLEANUPS);
683
684 restore_cleanups (saved_cleanup_chain);
685
686 memcpy (error_return, saved_error_return, sizeof (jmp_buf));
687
688 return val;
689 }
690
691 static int
692 gdb_listfiles (clientData, interp, argc, argv)
693 ClientData clientData;
694 Tcl_Interp *interp;
695 int argc;
696 char *argv[];
697 {
698 int val;
699 struct objfile *objfile;
700 struct partial_symtab *psymtab;
701 struct symtab *symtab;
702
703 ALL_PSYMTABS (objfile, psymtab)
704 Tcl_AppendElement (interp, psymtab->filename);
705
706 ALL_SYMTABS (objfile, symtab)
707 Tcl_AppendElement (interp, symtab->filename);
708
709 return TCL_OK;
710 }
711
712 static int
713 gdb_stop (clientData, interp, argc, argv)
714 ClientData clientData;
715 Tcl_Interp *interp;
716 int argc;
717 char *argv[];
718 {
719 target_stop ();
720
721 return TCL_OK;
722 }
723 \f
724 /* This implements the TCL command `gdb_disassemble'. */
725
726 static int
727 gdbtk_dis_asm_read_memory (memaddr, myaddr, len, info)
728 bfd_vma memaddr;
729 bfd_byte *myaddr;
730 int len;
731 disassemble_info *info;
732 {
733 extern struct target_ops exec_ops;
734 int res;
735
736 errno = 0;
737 res = xfer_memory (memaddr, myaddr, len, 0, &exec_ops);
738
739 if (res == len)
740 return 0;
741 else
742 if (errno == 0)
743 return EIO;
744 else
745 return errno;
746 }
747
748 /* We need a different sort of line table from the normal one cuz we can't
749 depend upon implicit line-end pc's for lines. This is because of the
750 reordering we are about to do. */
751
752 struct my_line_entry {
753 int line;
754 CORE_ADDR start_pc;
755 CORE_ADDR end_pc;
756 };
757
758 static int
759 compare_lines (mle1p, mle2p)
760 const PTR mle1p;
761 const PTR mle2p;
762 {
763 struct my_line_entry *mle1, *mle2;
764 int val;
765
766 mle1 = (struct my_line_entry *) mle1p;
767 mle2 = (struct my_line_entry *) mle2p;
768
769 val = mle1->line - mle2->line;
770
771 if (val != 0)
772 return val;
773
774 return mle1->start_pc - mle2->start_pc;
775 }
776
777 static int
778 gdb_disassemble (clientData, interp, argc, argv)
779 ClientData clientData;
780 Tcl_Interp *interp;
781 int argc;
782 char *argv[];
783 {
784 CORE_ADDR pc, low, high;
785 int mixed_source_and_assembly;
786
787 if (argc != 3 && argc != 4)
788 {
789 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
790 return TCL_ERROR;
791 }
792
793 if (strcmp (argv[1], "source") == 0)
794 mixed_source_and_assembly = 1;
795 else if (strcmp (argv[1], "nosource") == 0)
796 mixed_source_and_assembly = 0;
797 else
798 {
799 Tcl_SetResult (interp, "First arg must be 'source' or 'nosource'",
800 TCL_STATIC);
801 return TCL_ERROR;
802 }
803
804 low = parse_and_eval_address (argv[2]);
805
806 if (argc == 3)
807 {
808 if (find_pc_partial_function (low, NULL, &low, &high) == 0)
809 {
810 Tcl_SetResult (interp, "No function contains specified address",
811 TCL_STATIC);
812 return TCL_ERROR;
813 }
814 }
815 else
816 high = parse_and_eval_address (argv[3]);
817
818 /* If disassemble_from_exec == -1, then we use the following heuristic to
819 determine whether or not to do disassembly from target memory or from the
820 exec file:
821
822 If we're debugging a local process, read target memory, instead of the
823 exec file. This makes disassembly of functions in shared libs work
824 correctly.
825
826 Else, we're debugging a remote process, and should disassemble from the
827 exec file for speed. However, this is no good if the target modifies it's
828 code (for relocation, or whatever).
829 */
830
831 if (disassemble_from_exec == -1)
832 if (strcmp (target_shortname, "child") == 0
833 || strcmp (target_shortname, "procfs") == 0)
834 disassemble_from_exec = 0; /* It's a child process, read inferior mem */
835 else
836 disassemble_from_exec = 1; /* It's remote, read the exec file */
837
838 if (disassemble_from_exec)
839 dis_asm_read_memory_hook = gdbtk_dis_asm_read_memory;
840
841 /* If just doing straight assembly, all we need to do is disassemble
842 everything between low and high. If doing mixed source/assembly, we've
843 got a totally different path to follow. */
844
845 if (mixed_source_and_assembly)
846 { /* Come here for mixed source/assembly */
847 /* The idea here is to present a source-O-centric view of a function to
848 the user. This means that things are presented in source order, with
849 (possibly) out of order assembly immediately following. */
850 struct symtab *symtab;
851 struct linetable_entry *le;
852 int nlines;
853 struct my_line_entry *mle;
854 struct symtab_and_line sal;
855 int i;
856 int out_of_order;
857 int current_line;
858
859 symtab = find_pc_symtab (low); /* Assume symtab is valid for whole PC range */
860
861 if (!symtab)
862 goto assembly_only;
863
864 /* First, convert the linetable to a bunch of my_line_entry's. */
865
866 le = symtab->linetable->item;
867 nlines = symtab->linetable->nitems;
868
869 if (nlines <= 0)
870 goto assembly_only;
871
872 mle = (struct my_line_entry *) alloca (nlines * sizeof (struct my_line_entry));
873
874 out_of_order = 0;
875
876 for (i = 0; i < nlines - 1; i++)
877 {
878 mle[i].line = le[i].line;
879 if (le[i].line > le[i + 1].line)
880 out_of_order = 1;
881 mle[i].start_pc = le[i].pc;
882 mle[i].end_pc = le[i + 1].pc;
883 }
884
885 mle[i].line = le[i].line;
886 mle[i].start_pc = le[i].pc;
887 sal = find_pc_line (le[i].pc, 0);
888 mle[i].end_pc = sal.end;
889
890 /* Now, sort mle by line #s (and, then by addresses within lines). */
891
892 if (out_of_order)
893 qsort (mle, nlines, sizeof (struct my_line_entry), compare_lines);
894
895 /* Scan forward until we find the start of the function. */
896
897 for (i = 0; i < nlines; i++)
898 if (mle[i].start_pc >= low)
899 break;
900
901 /* Now, for each line entry, emit the specified lines (unless they have been
902 emitted before), followed by the assembly code for that line. */
903
904 current_line = 0; /* Force out first line */
905 for (;i < nlines && mle[i].start_pc < high; i++)
906 {
907 if (mle[i].line > current_line)
908 {
909 if (i == nlines - 1)
910 print_source_lines (symtab, mle[i].line, INT_MAX, 0);
911 else
912 print_source_lines (symtab, mle[i].line, mle[i + 1].line, 0);
913 current_line = mle[i].line;
914 }
915 for (pc = mle[i].start_pc; pc < mle[i].end_pc; )
916 {
917 QUIT;
918 fputs_unfiltered (" ", gdb_stdout);
919 print_address (pc, gdb_stdout);
920 fputs_unfiltered (":\t ", gdb_stdout);
921 pc += print_insn (pc, gdb_stdout);
922 fputs_unfiltered ("\n", gdb_stdout);
923 }
924 }
925 }
926 else
927 {
928 assembly_only:
929 for (pc = low; pc < high; )
930 {
931 QUIT;
932 fputs_unfiltered (" ", gdb_stdout);
933 print_address (pc, gdb_stdout);
934 fputs_unfiltered (":\t ", gdb_stdout);
935 pc += print_insn (pc, gdb_stdout);
936 fputs_unfiltered ("\n", gdb_stdout);
937 }
938 }
939
940 dis_asm_read_memory_hook = 0;
941
942 gdb_flush (gdb_stdout);
943
944 return TCL_OK;
945 }
946 \f
947 static void
948 tk_command (cmd, from_tty)
949 char *cmd;
950 int from_tty;
951 {
952 int retval;
953 char *result;
954 struct cleanup *old_chain;
955
956 retval = Tcl_Eval (interp, cmd);
957
958 result = strdup (interp->result);
959
960 old_chain = make_cleanup (free, result);
961
962 if (retval != TCL_OK)
963 error (result);
964
965 printf_unfiltered ("%s\n", result);
966
967 do_cleanups (old_chain);
968 }
969
970 static void
971 cleanup_init (ignored)
972 int ignored;
973 {
974 if (mainWindow != NULL)
975 Tk_DestroyWindow (mainWindow);
976 mainWindow = NULL;
977
978 if (interp != NULL)
979 Tcl_DeleteInterp (interp);
980 interp = NULL;
981 }
982
983 /* Come here during long calculations to check for GUI events. Usually invoked
984 via the QUIT macro. */
985
986 static void
987 gdbtk_interactive ()
988 {
989 /* Tk_DoOneEvent (TK_DONT_WAIT|TK_IDLE_EVENTS); */
990 }
991
992 /* Come here when there is activity on the X file descriptor. */
993
994 static void
995 x_event (signo)
996 int signo;
997 {
998 /* Process pending events */
999
1000 while (Tk_DoOneEvent (TK_DONT_WAIT|TK_ALL_EVENTS) != 0);
1001 }
1002
1003 static int
1004 gdbtk_wait (pid, ourstatus)
1005 int pid;
1006 struct target_waitstatus *ourstatus;
1007 {
1008 struct sigaction action;
1009 static sigset_t nullsigmask = {0};
1010
1011 #ifndef SA_RESTART
1012 /* Needed for SunOS 4.1.x */
1013 #define SA_RESTART 0
1014 #endif
1015
1016 action.sa_handler = x_event;
1017 action.sa_mask = nullsigmask;
1018 action.sa_flags = SA_RESTART;
1019 sigaction(SIGIO, &action, NULL);
1020
1021 pid = target_wait (pid, ourstatus);
1022
1023 action.sa_handler = SIG_IGN;
1024 sigaction(SIGIO, &action, NULL);
1025
1026 return pid;
1027 }
1028
1029 /* This is called from execute_command, and provides a wrapper around
1030 various command routines in a place where both protocol messages and
1031 user input both flow through. Mostly this is used for indicating whether
1032 the target process is running or not.
1033 */
1034
1035 static void
1036 gdbtk_call_command (cmdblk, arg, from_tty)
1037 struct cmd_list_element *cmdblk;
1038 char *arg;
1039 int from_tty;
1040 {
1041 if (cmdblk->class == class_run)
1042 {
1043 Tcl_VarEval (interp, "gdbtk_tcl_busy", NULL);
1044 (*cmdblk->function.cfunc)(arg, from_tty);
1045 Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL);
1046 }
1047 else
1048 (*cmdblk->function.cfunc)(arg, from_tty);
1049 }
1050
1051 static void
1052 gdbtk_init ()
1053 {
1054 struct cleanup *old_chain;
1055 char *gdbtk_filename;
1056 int i;
1057 struct sigaction action;
1058 static sigset_t nullsigmask = {0};
1059 extern struct cmd_list_element *setlist;
1060 extern struct cmd_list_element *showlist;
1061
1062 old_chain = make_cleanup (cleanup_init, 0);
1063
1064 /* First init tcl and tk. */
1065
1066 interp = Tcl_CreateInterp ();
1067
1068 if (!interp)
1069 error ("Tcl_CreateInterp failed");
1070
1071 Tcl_DStringInit (&stdout_buffer); /* Setup stdout buffer */
1072
1073 mainWindow = Tk_CreateMainWindow (interp, NULL, "gdb", "Gdb");
1074
1075 if (!mainWindow)
1076 return; /* DISPLAY probably not set */
1077
1078 if (Tcl_Init(interp) != TCL_OK)
1079 error ("Tcl_Init failed: %s", interp->result);
1080
1081 if (Tk_Init(interp) != TCL_OK)
1082 error ("Tk_Init failed: %s", interp->result);
1083
1084 Tcl_CreateCommand (interp, "gdb_cmd", call_wrapper, gdb_cmd, NULL);
1085 Tcl_CreateCommand (interp, "gdb_loc", call_wrapper, gdb_loc, NULL);
1086 Tcl_CreateCommand (interp, "gdb_sourcelines", call_wrapper, gdb_sourcelines,
1087 NULL);
1088 Tcl_CreateCommand (interp, "gdb_listfiles", call_wrapper, gdb_listfiles,
1089 NULL);
1090 Tcl_CreateCommand (interp, "gdb_stop", call_wrapper, gdb_stop, NULL);
1091 Tcl_CreateCommand (interp, "gdb_regnames", call_wrapper, gdb_regnames, NULL);
1092 Tcl_CreateCommand (interp, "gdb_fetch_registers", call_wrapper,
1093 gdb_fetch_registers, NULL);
1094 Tcl_CreateCommand (interp, "gdb_changed_register_list", call_wrapper,
1095 gdb_changed_register_list, NULL);
1096 Tcl_CreateCommand (interp, "gdb_disassemble", call_wrapper,
1097 gdb_disassemble, NULL);
1098 Tcl_CreateCommand (interp, "gdb_eval", call_wrapper, gdb_eval, NULL);
1099
1100 command_loop_hook = Tk_MainLoop;
1101 print_frame_info_listing_hook = null_routine;
1102 query_hook = gdbtk_query;
1103 flush_hook = gdbtk_flush;
1104 create_breakpoint_hook = gdbtk_create_breakpoint;
1105 delete_breakpoint_hook = gdbtk_delete_breakpoint;
1106 enable_breakpoint_hook = gdbtk_enable_breakpoint;
1107 disable_breakpoint_hook = gdbtk_disable_breakpoint;
1108 interactive_hook = gdbtk_interactive;
1109 target_wait_hook = gdbtk_wait;
1110 call_command_hook = gdbtk_call_command;
1111
1112 /* Get the file descriptor for the X server */
1113
1114 x_fd = ConnectionNumber (Tk_Display (mainWindow));
1115
1116 /* Setup for I/O interrupts */
1117
1118 action.sa_mask = nullsigmask;
1119 action.sa_flags = 0;
1120 action.sa_handler = SIG_IGN;
1121 sigaction(SIGIO, &action, NULL);
1122
1123 #ifdef FIOASYNC
1124 i = 1;
1125 if (ioctl (x_fd, FIOASYNC, &i))
1126 perror_with_name ("gdbtk_init: ioctl FIOASYNC failed");
1127
1128 i = getpid();
1129 if (ioctl (x_fd, SIOCSPGRP, &i))
1130 perror_with_name ("gdbtk_init: ioctl SIOCSPGRP failed");
1131 #else
1132 if (ioctl (x_fd, I_SETSIG, S_INPUT|S_RDNORM) < 0)
1133 perror_with_name ("gdbtk_init: ioctl I_SETSIG failed");
1134 #endif /* ifndef FIOASYNC */
1135
1136 add_com ("tk", class_obscure, tk_command,
1137 "Send a command directly into tk.");
1138
1139 #if 0
1140 add_show_from_set (add_set_cmd ("disassemble-from-exec", class_support,
1141 var_boolean, (char *)&disassemble_from_exec,
1142 "Set ", &setlist),
1143 &showlist);
1144 #endif
1145
1146 Tcl_LinkVar (interp, "disassemble-from-exec", (char *)&disassemble_from_exec,
1147 TCL_LINK_INT);
1148
1149 /* Load up gdbtk.tcl after all the environment stuff has been setup. */
1150
1151 gdbtk_filename = getenv ("GDBTK_FILENAME");
1152 if (!gdbtk_filename)
1153 if (access ("gdbtk.tcl", R_OK) == 0)
1154 gdbtk_filename = "gdbtk.tcl";
1155 else
1156 gdbtk_filename = GDBTK_FILENAME;
1157
1158 /* Defer setup of fputs_unfiltered_hook to near the end so that error messages
1159 prior to this point go to stdout/stderr. */
1160
1161 fputs_unfiltered_hook = gdbtk_fputs;
1162
1163 if (Tcl_EvalFile (interp, gdbtk_filename) != TCL_OK)
1164 {
1165 fputs_unfiltered_hook = NULL; /* Force errors to stdout/stderr */
1166
1167 fprintf_unfiltered (stderr, "%s:%d: %s\n", gdbtk_filename,
1168 interp->errorLine, interp->result);
1169 error ("Stack trace:\n%s", Tcl_GetVar (interp, "errorInfo", 0));
1170 }
1171
1172 discard_cleanups (old_chain);
1173 }
1174
1175 /* Come here during initialze_all_files () */
1176
1177 void
1178 _initialize_gdbtk ()
1179 {
1180 if (use_windows)
1181 {
1182 /* Tell the rest of the world that Gdbtk is now set up. */
1183
1184 init_ui_hook = gdbtk_init;
1185 }
1186 }
This page took 0.055308 seconds and 4 git commands to generate.