]> Git Repo - binutils.git/blame - gdb/gdbtk.c
* array-rom.c: Remove the non GDB remote protocol config stuff.
[binutils.git] / gdb / gdbtk.c
CommitLineData
4604b34c
SG
1/* Tcl/Tk interface routines.
2 Copyright 1994, 1995 Free Software Foundation, Inc.
3
4 Written by Stu Grossman <[email protected]> of Cygnus Support.
754e5da2
SG
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"
754e5da2
SG
30#include <tcl.h>
31#include <tk.h>
cd2df226
SG
32#include <varargs.h>
33#include <signal.h>
34#include <fcntl.h>
8532893d 35#include <unistd.h>
86db943c
SG
36#include <setjmp.h>
37#include "top.h"
736a82e7
SG
38#include <sys/ioctl.h>
39#include <string.h>
09722039 40#include "dis-asm.h"
736a82e7
SG
41
42#ifndef FIOASYNC
546b8ca7
SG
43#include <sys/stropts.h>
44#endif
754e5da2
SG
45
46/* Non-zero means that we're doing the gdbtk interface. */
47int gdbtk = 0;
48
49/* Non-zero means we are reloading breakpoints, etc from the
50 Gdbtk kernel, and we should suppress various messages */
51static int gdbtk_reloading = 0;
52
53/* Handle for TCL interpreter */
54static Tcl_Interp *interp = NULL;
55
56/* Handle for TK main window */
57static Tk_Window mainWindow = NULL;
58
479f0f18
SG
59static int x_fd; /* X network socket */
60
09722039
SG
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
70static int disassemble_from_exec = -1;
71
754e5da2
SG
72static void
73null_routine(arg)
74 int arg;
75{
76}
77
546b8ca7
SG
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.
86db943c 84
546b8ca7
SG
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). */
86db943c 91
546b8ca7 92/* Dynamic string header for stdout. */
86db943c 93
546b8ca7 94static Tcl_DString stdout_buffer;
86db943c 95
546b8ca7
SG
96/* Use this to collect stdout output that will be returned as the result of a
97 tcl command. */
86db943c 98
546b8ca7 99static int saving_output = 0;
86db943c 100
546b8ca7
SG
101static void
102start_saving_output ()
103{
104 saving_output = 1;
86db943c
SG
105}
106
546b8ca7 107#define get_saved_output() (Tcl_DStringValue (&stdout_buffer))
86db943c
SG
108
109static void
110finish_saving_output ()
111{
09722039
SG
112 if (!saving_output)
113 return;
114
546b8ca7 115 saving_output = 0;
86db943c 116
546b8ca7 117 Tcl_DStringFree (&stdout_buffer);
86db943c 118}
754e5da2
SG
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
123static void
8532893d 124flush_holdbuf ()
754e5da2 125{
546b8ca7
SG
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);
8532893d 132
546b8ca7
SG
133 Tcl_DStringFree (&stdout_buffer);
134
135 Tcl_VarEval (interp, "gdbtk_tcl_fputs ", s, NULL);
136
137 free (s);
754e5da2
SG
138}
139
140static void
141gdbtk_flush (stream)
142 FILE *stream;
143{
546b8ca7 144 if (stream != gdb_stdout || saving_output)
86db943c
SG
145 return;
146
147 /* Flush output from C to tcl land. */
148
8532893d
SG
149 flush_holdbuf ();
150
86db943c
SG
151 /* Force immediate screen update */
152
754e5da2
SG
153 Tcl_VarEval (interp, "gdbtk_tcl_flush", NULL);
154}
155
8532893d 156static void
86db943c 157gdbtk_fputs (ptr, stream)
8532893d 158 const char *ptr;
86db943c 159 FILE *stream;
8532893d
SG
160{
161 int len;
162
86db943c
SG
163 if (stream != gdb_stdout)
164 {
165 Tcl_VarEval (interp, "gdbtk_tcl_fputs_error ", "{", ptr, "}", NULL);
166 return;
167 }
168
546b8ca7 169 Tcl_DStringAppend (&stdout_buffer, ptr, -1);
8532893d 170
546b8ca7
SG
171 if (saving_output)
172 return;
8532893d 173
546b8ca7
SG
174 if (Tcl_DStringLength (&stdout_buffer) > 1000)
175 flush_holdbuf ();
8532893d
SG
176}
177
754e5da2
SG
178static int
179gdbtk_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
754e5da2
SG
195static void
196breakpoint_notify(b, action)
197 struct breakpoint *b;
198 const char *action;
199{
200 struct symbol *sym;
8532893d 201 char bpnum[50], line[50], pc[50];
754e5da2
SG
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
637b1661 211 filename = symtab_to_filename (sal.symtab);
754e5da2
SG
212
213 sprintf (bpnum, "%d", b->number);
214 sprintf (line, "%d", sal.line);
546b8ca7 215 sprintf (pc, "0x%lx", b->address);
754e5da2
SG
216
217 v = Tcl_VarEval (interp,
218 "gdbtk_tcl_breakpoint ",
219 action,
220 " ", bpnum,
09722039 221 " ", filename ? filename : "{}",
754e5da2 222 " ", line,
8532893d 223 " ", pc,
754e5da2
SG
224 NULL);
225
226 if (v != TCL_OK)
227 {
546b8ca7
SG
228 gdbtk_fputs (interp->result, gdb_stdout);
229 gdbtk_fputs ("\n", gdb_stdout);
754e5da2 230 }
754e5da2
SG
231}
232
233static void
234gdbtk_create_breakpoint(b)
235 struct breakpoint *b;
236{
237 breakpoint_notify(b, "create");
238}
239
240static void
241gdbtk_delete_breakpoint(b)
242 struct breakpoint *b;
243{
244 breakpoint_notify(b, "delete");
245}
246
247static void
248gdbtk_enable_breakpoint(b)
249 struct breakpoint *b;
250{
251 breakpoint_notify(b, "enable");
252}
253
254static void
255gdbtk_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
264static int
265gdb_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;
8532893d 275 CORE_ADDR pc;
754e5da2
SG
276
277 if (argc == 1)
278 {
1dfc8dfb 279 pc = selected_frame ? selected_frame->pc : stop_pc;
754e5da2
SG
280 sal = find_pc_line (pc, 0);
281 }
282 else if (argc == 2)
283 {
754e5da2 284 struct symtabs_and_lines sals;
8532893d 285 int nelts;
754e5da2
SG
286
287 sals = decode_line_spec (argv[1], 1);
288
8532893d
SG
289 nelts = sals.nelts;
290 sal = sals.sals[0];
291 free (sals.sals);
292
754e5da2
SG
293 if (sals.nelts != 1)
294 {
295 Tcl_SetResult (interp, "Ambiguous line spec", TCL_STATIC);
754e5da2
SG
296 return TCL_ERROR;
297 }
298
8532893d 299 pc = sal.pc;
754e5da2
SG
300 }
301 else
302 {
303 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
304 return TCL_ERROR;
305 }
306
754e5da2
SG
307 if (sal.symtab)
308 Tcl_AppendElement (interp, sal.symtab->filename);
309 else
310 Tcl_AppendElement (interp, "");
8532893d
SG
311
312 find_pc_partial_function (pc, &funcname, NULL, NULL);
754e5da2 313 Tcl_AppendElement (interp, funcname);
8532893d 314
637b1661 315 filename = symtab_to_filename (sal.symtab);
754e5da2 316 Tcl_AppendElement (interp, filename);
8532893d
SG
317
318 sprintf (buf, "%d", sal.line);
754e5da2
SG
319 Tcl_AppendElement (interp, buf); /* line number */
320
546b8ca7 321 sprintf (buf, "0x%lx", pc);
8532893d
SG
322 Tcl_AppendElement (interp, buf); /* PC */
323
754e5da2
SG
324 return TCL_OK;
325}
326\f
09722039
SG
327/* This implements the TCL command `gdb_eval'. */
328
329static int
330gdb_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
5b21fb68
SG
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
373static int
374gdb_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
746d1df4
SG
426static int
427map_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
474static int
475get_register_name (regnum, argp)
476 int regnum;
477 void *argp; /* Ignored */
478{
479 Tcl_AppendElement (interp, reg_names[regnum]);
480}
481
5b21fb68
SG
482/* This implements the TCL command `gdb_regnames', which returns a list of
483 all of the register names. */
484
485static int
486gdb_regnames (clientData, interp, argc, argv)
487 ClientData clientData;
488 Tcl_Interp *interp;
489 int argc;
490 char *argv[];
491{
746d1df4
SG
492 argc--;
493 argv++;
494
495 return map_arg_registers (argc, argv, get_register_name, 0);
496}
497
746d1df4
SG
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
510static int
511get_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
86db943c 524 start_saving_output (); /* Start collecting stdout */
746d1df4
SG
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
86db943c 539 Tcl_AppendElement (interp, get_saved_output ());
746d1df4 540
86db943c 541 finish_saving_output (); /* Set stdout back to normal */
746d1df4
SG
542}
543
544static int
545gdb_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)
5b21fb68
SG
554 {
555 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
556 return TCL_ERROR;
557 }
558
746d1df4
SG
559 argc--;
560 argv++;
5b21fb68 561
746d1df4
SG
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
571static char old_regs[REGISTER_BYTES];
572
573static int
574register_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
596static int
597gdb_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);
5b21fb68
SG
609}
610\f
754e5da2
SG
611/* This implements the TCL command `gdb_cmd', which sends it's argument into
612 the GDB command scanner. */
613
614static int
615gdb_cmd (clientData, interp, argc, argv)
616 ClientData clientData;
617 Tcl_Interp *interp;
618 int argc;
619 char *argv[];
620{
754e5da2
SG
621 if (argc != 2)
622 {
623 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
624 return TCL_ERROR;
625 }
626
86db943c 627 execute_command (argv[1], 1);
479f0f18 628
754e5da2 629 bpstat_do_actions (&stop_bpstat);
754e5da2 630
8532893d
SG
631 /* Drain all buffered command output */
632
8532893d
SG
633 gdb_flush (gdb_stdout);
634
754e5da2
SG
635 return TCL_OK;
636}
637
86db943c
SG
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
645static int
646call_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
09722039
SG
670 dis_asm_read_memory_hook = 0; /* Restore disassembly hook */
671
86db943c
SG
672 gdb_flush (gdb_stderr); /* Flush error output */
673
09722039
SG
674 gdb_flush (gdb_stdout); /* Sometimes error output comes here as well */
675
86db943c
SG
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
754e5da2
SG
691static int
692gdb_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;
546b8ca7 701 struct symtab *symtab;
754e5da2
SG
702
703 ALL_PSYMTABS (objfile, psymtab)
704 Tcl_AppendElement (interp, psymtab->filename);
705
546b8ca7
SG
706 ALL_SYMTABS (objfile, symtab)
707 Tcl_AppendElement (interp, symtab->filename);
708
754e5da2
SG
709 return TCL_OK;
710}
479f0f18
SG
711
712static int
713gdb_stop (clientData, interp, argc, argv)
714 ClientData clientData;
715 Tcl_Interp *interp;
716 int argc;
717 char *argv[];
718{
6c27841f 719 target_stop ();
546b8ca7
SG
720
721 return TCL_OK;
479f0f18 722}
09722039
SG
723\f
724/* This implements the TCL command `gdb_disassemble'. */
479f0f18 725
09722039
SG
726static int
727gdbtk_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
752struct my_line_entry {
753 int line;
754 CORE_ADDR start_pc;
755 CORE_ADDR end_pc;
756};
757
758static int
759compare_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
777static int
778gdb_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;
c81a3fa9 853 int newlines;
09722039
SG
854 struct my_line_entry *mle;
855 struct symtab_and_line sal;
856 int i;
857 int out_of_order;
c81a3fa9 858 int next_line;
09722039
SG
859
860 symtab = find_pc_symtab (low); /* Assume symtab is valid for whole PC range */
861
862 if (!symtab)
863 goto assembly_only;
864
865/* First, convert the linetable to a bunch of my_line_entry's. */
866
867 le = symtab->linetable->item;
868 nlines = symtab->linetable->nitems;
869
870 if (nlines <= 0)
871 goto assembly_only;
872
873 mle = (struct my_line_entry *) alloca (nlines * sizeof (struct my_line_entry));
874
875 out_of_order = 0;
876
c81a3fa9
SG
877/* Copy linetable entries for this function into our data structure, creating
878 end_pc's and setting out_of_order as appropriate. */
879
880/* First, skip all the preceding functions. */
881
882 for (i = 0; i < nlines - 1 && le[i].pc < low; i++) ;
883
884/* Now, copy all entries before the end of this function. */
885
886 newlines = 0;
887 for (; i < nlines - 1 && le[i].pc < high; i++)
09722039 888 {
c81a3fa9
SG
889 if (le[i].line == le[i + 1].line
890 && le[i].pc == le[i + 1].pc)
891 continue; /* Ignore duplicates */
892
893 mle[newlines].line = le[i].line;
09722039
SG
894 if (le[i].line > le[i + 1].line)
895 out_of_order = 1;
c81a3fa9
SG
896 mle[newlines].start_pc = le[i].pc;
897 mle[newlines].end_pc = le[i + 1].pc;
898 newlines++;
09722039
SG
899 }
900
c81a3fa9
SG
901/* If we're on the last line, and it's part of the function, then we need to
902 get the end pc in a special way. */
903
904 if (i == nlines - 1
905 && le[i].pc < high)
906 {
907 mle[newlines].line = le[i].line;
908 mle[newlines].start_pc = le[i].pc;
909 sal = find_pc_line (le[i].pc, 0);
910 mle[newlines].end_pc = sal.end;
911 newlines++;
912 }
09722039
SG
913
914/* Now, sort mle by line #s (and, then by addresses within lines). */
915
916 if (out_of_order)
c81a3fa9 917 qsort (mle, newlines, sizeof (struct my_line_entry), compare_lines);
09722039
SG
918
919/* Now, for each line entry, emit the specified lines (unless they have been
920 emitted before), followed by the assembly code for that line. */
921
c81a3fa9
SG
922 next_line = 0; /* Force out first line */
923 for (i = 0; i < newlines; i++)
09722039 924 {
c81a3fa9
SG
925/* Print out everything from next_line to the current line. */
926
927 if (mle[i].line >= next_line)
09722039 928 {
c81a3fa9
SG
929 if (next_line != 0)
930 print_source_lines (symtab, next_line, mle[i].line + 1, 0);
09722039 931 else
c81a3fa9
SG
932 print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
933
934 next_line = mle[i].line + 1;
09722039 935 }
c81a3fa9 936
09722039
SG
937 for (pc = mle[i].start_pc; pc < mle[i].end_pc; )
938 {
939 QUIT;
940 fputs_unfiltered (" ", gdb_stdout);
941 print_address (pc, gdb_stdout);
942 fputs_unfiltered (":\t ", gdb_stdout);
943 pc += print_insn (pc, gdb_stdout);
944 fputs_unfiltered ("\n", gdb_stdout);
945 }
946 }
947 }
948 else
949 {
950assembly_only:
951 for (pc = low; pc < high; )
952 {
953 QUIT;
954 fputs_unfiltered (" ", gdb_stdout);
955 print_address (pc, gdb_stdout);
956 fputs_unfiltered (":\t ", gdb_stdout);
957 pc += print_insn (pc, gdb_stdout);
958 fputs_unfiltered ("\n", gdb_stdout);
959 }
960 }
961
962 dis_asm_read_memory_hook = 0;
963
964 gdb_flush (gdb_stdout);
965
966 return TCL_OK;
967}
754e5da2
SG
968\f
969static void
970tk_command (cmd, from_tty)
971 char *cmd;
972 int from_tty;
973{
546b8ca7
SG
974 int retval;
975 char *result;
976 struct cleanup *old_chain;
977
978 retval = Tcl_Eval (interp, cmd);
979
980 result = strdup (interp->result);
754e5da2 981
546b8ca7
SG
982 old_chain = make_cleanup (free, result);
983
984 if (retval != TCL_OK)
985 error (result);
986
987 printf_unfiltered ("%s\n", result);
988
989 do_cleanups (old_chain);
754e5da2
SG
990}
991
992static void
993cleanup_init (ignored)
994 int ignored;
995{
996 if (mainWindow != NULL)
997 Tk_DestroyWindow (mainWindow);
998 mainWindow = NULL;
999
1000 if (interp != NULL)
1001 Tcl_DeleteInterp (interp);
1002 interp = NULL;
1003}
1004
637b1661
SG
1005/* Come here during long calculations to check for GUI events. Usually invoked
1006 via the QUIT macro. */
1007
1008static void
1009gdbtk_interactive ()
1010{
1011 /* Tk_DoOneEvent (TK_DONT_WAIT|TK_IDLE_EVENTS); */
1012}
1013
479f0f18
SG
1014/* Come here when there is activity on the X file descriptor. */
1015
1016static void
1017x_event (signo)
1018 int signo;
1019{
1020 /* Process pending events */
1021
1022 while (Tk_DoOneEvent (TK_DONT_WAIT|TK_ALL_EVENTS) != 0);
1023}
1024
1025static int
1026gdbtk_wait (pid, ourstatus)
1027 int pid;
1028 struct target_waitstatus *ourstatus;
1029{
736a82e7
SG
1030 struct sigaction action;
1031 static sigset_t nullsigmask = {0};
1032
1033#ifndef SA_RESTART
1034 /* Needed for SunOS 4.1.x */
1035#define SA_RESTART 0
546b8ca7 1036#endif
479f0f18 1037
736a82e7
SG
1038 action.sa_handler = x_event;
1039 action.sa_mask = nullsigmask;
1040 action.sa_flags = SA_RESTART;
1041 sigaction(SIGIO, &action, NULL);
1042
479f0f18
SG
1043 pid = target_wait (pid, ourstatus);
1044
736a82e7
SG
1045 action.sa_handler = SIG_IGN;
1046 sigaction(SIGIO, &action, NULL);
479f0f18
SG
1047
1048 return pid;
1049}
1050
1051/* This is called from execute_command, and provides a wrapper around
1052 various command routines in a place where both protocol messages and
1053 user input both flow through. Mostly this is used for indicating whether
1054 the target process is running or not.
1055*/
1056
1057static void
1058gdbtk_call_command (cmdblk, arg, from_tty)
1059 struct cmd_list_element *cmdblk;
1060 char *arg;
1061 int from_tty;
1062{
1063 if (cmdblk->class == class_run)
1064 {
1065 Tcl_VarEval (interp, "gdbtk_tcl_busy", NULL);
1066 (*cmdblk->function.cfunc)(arg, from_tty);
1067 Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL);
1068 }
1069 else
1070 (*cmdblk->function.cfunc)(arg, from_tty);
1071}
1072
754e5da2
SG
1073static void
1074gdbtk_init ()
1075{
1076 struct cleanup *old_chain;
1077 char *gdbtk_filename;
479f0f18 1078 int i;
736a82e7
SG
1079 struct sigaction action;
1080 static sigset_t nullsigmask = {0};
09722039
SG
1081 extern struct cmd_list_element *setlist;
1082 extern struct cmd_list_element *showlist;
754e5da2
SG
1083
1084 old_chain = make_cleanup (cleanup_init, 0);
1085
1086 /* First init tcl and tk. */
1087
1088 interp = Tcl_CreateInterp ();
1089
1090 if (!interp)
1091 error ("Tcl_CreateInterp failed");
1092
546b8ca7
SG
1093 Tcl_DStringInit (&stdout_buffer); /* Setup stdout buffer */
1094
754e5da2
SG
1095 mainWindow = Tk_CreateMainWindow (interp, NULL, "gdb", "Gdb");
1096
1097 if (!mainWindow)
1098 return; /* DISPLAY probably not set */
1099
1100 if (Tcl_Init(interp) != TCL_OK)
1101 error ("Tcl_Init failed: %s", interp->result);
1102
1103 if (Tk_Init(interp) != TCL_OK)
1104 error ("Tk_Init failed: %s", interp->result);
1105
86db943c
SG
1106 Tcl_CreateCommand (interp, "gdb_cmd", call_wrapper, gdb_cmd, NULL);
1107 Tcl_CreateCommand (interp, "gdb_loc", call_wrapper, gdb_loc, NULL);
1108 Tcl_CreateCommand (interp, "gdb_sourcelines", call_wrapper, gdb_sourcelines,
1109 NULL);
1110 Tcl_CreateCommand (interp, "gdb_listfiles", call_wrapper, gdb_listfiles,
746d1df4 1111 NULL);
86db943c
SG
1112 Tcl_CreateCommand (interp, "gdb_stop", call_wrapper, gdb_stop, NULL);
1113 Tcl_CreateCommand (interp, "gdb_regnames", call_wrapper, gdb_regnames, NULL);
1114 Tcl_CreateCommand (interp, "gdb_fetch_registers", call_wrapper,
1115 gdb_fetch_registers, NULL);
1116 Tcl_CreateCommand (interp, "gdb_changed_register_list", call_wrapper,
1117 gdb_changed_register_list, NULL);
09722039
SG
1118 Tcl_CreateCommand (interp, "gdb_disassemble", call_wrapper,
1119 gdb_disassemble, NULL);
1120 Tcl_CreateCommand (interp, "gdb_eval", call_wrapper, gdb_eval, NULL);
754e5da2 1121
09722039 1122 command_loop_hook = Tk_MainLoop;
09722039
SG
1123 print_frame_info_listing_hook = null_routine;
1124 query_hook = gdbtk_query;
1125 flush_hook = gdbtk_flush;
1126 create_breakpoint_hook = gdbtk_create_breakpoint;
1127 delete_breakpoint_hook = gdbtk_delete_breakpoint;
1128 enable_breakpoint_hook = gdbtk_enable_breakpoint;
1129 disable_breakpoint_hook = gdbtk_disable_breakpoint;
1130 interactive_hook = gdbtk_interactive;
1131 target_wait_hook = gdbtk_wait;
1132 call_command_hook = gdbtk_call_command;
754e5da2 1133
cd2df226 1134 /* Get the file descriptor for the X server */
479f0f18 1135
cd2df226 1136 x_fd = ConnectionNumber (Tk_Display (mainWindow));
479f0f18
SG
1137
1138 /* Setup for I/O interrupts */
1139
736a82e7
SG
1140 action.sa_mask = nullsigmask;
1141 action.sa_flags = 0;
1142 action.sa_handler = SIG_IGN;
1143 sigaction(SIGIO, &action, NULL);
1144
1145#ifdef FIOASYNC
1146 i = 1;
1147 if (ioctl (x_fd, FIOASYNC, &i))
1148 perror_with_name ("gdbtk_init: ioctl FIOASYNC failed");
479f0f18 1149
736a82e7
SG
1150 i = getpid();
1151 if (ioctl (x_fd, SIOCSPGRP, &i))
1152 perror_with_name ("gdbtk_init: ioctl SIOCSPGRP failed");
546b8ca7
SG
1153#else
1154 if (ioctl (x_fd, I_SETSIG, S_INPUT|S_RDNORM) < 0)
736a82e7
SG
1155 perror_with_name ("gdbtk_init: ioctl I_SETSIG failed");
1156#endif /* ifndef FIOASYNC */
479f0f18 1157
754e5da2
SG
1158 add_com ("tk", class_obscure, tk_command,
1159 "Send a command directly into tk.");
09722039
SG
1160
1161#if 0
1162 add_show_from_set (add_set_cmd ("disassemble-from-exec", class_support,
1163 var_boolean, (char *)&disassemble_from_exec,
1164 "Set ", &setlist),
1165 &showlist);
1166#endif
1167
1168 Tcl_LinkVar (interp, "disassemble-from-exec", (char *)&disassemble_from_exec,
1169 TCL_LINK_INT);
1170
1171 /* Load up gdbtk.tcl after all the environment stuff has been setup. */
1172
1173 gdbtk_filename = getenv ("GDBTK_FILENAME");
1174 if (!gdbtk_filename)
1175 if (access ("gdbtk.tcl", R_OK) == 0)
1176 gdbtk_filename = "gdbtk.tcl";
1177 else
1178 gdbtk_filename = GDBTK_FILENAME;
1179
724498fd
SG
1180/* Defer setup of fputs_unfiltered_hook to near the end so that error messages
1181 prior to this point go to stdout/stderr. */
1182
1183 fputs_unfiltered_hook = gdbtk_fputs;
1184
09722039 1185 if (Tcl_EvalFile (interp, gdbtk_filename) != TCL_OK)
724498fd 1186 {
b66051ec
SG
1187 char *err;
1188
724498fd
SG
1189 fputs_unfiltered_hook = NULL; /* Force errors to stdout/stderr */
1190
1191 fprintf_unfiltered (stderr, "%s:%d: %s\n", gdbtk_filename,
1192 interp->errorLine, interp->result);
b66051ec
SG
1193
1194 fputs_unfiltered ("Stack trace:\n", gdb_stderr);
1195 fputs_unfiltered (Tcl_GetVar (interp, "errorInfo", 0), gdb_stderr);
1196 error ("");
724498fd 1197 }
09722039
SG
1198
1199 discard_cleanups (old_chain);
754e5da2
SG
1200}
1201
1202/* Come here during initialze_all_files () */
1203
1204void
1205_initialize_gdbtk ()
1206{
c5197511
SG
1207 if (use_windows)
1208 {
1209 /* Tell the rest of the world that Gdbtk is now set up. */
754e5da2 1210
c5197511
SG
1211 init_ui_hook = gdbtk_init;
1212 }
754e5da2 1213}
This page took 0.228737 seconds and 4 git commands to generate.