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