+Thu Jul 28 14:37:36 1994 Stu Grossman (grossman@cygnus.com)
+
+ * Makefile.in (INSTALLED_LIBS, CLIBS, DEPFILES): Add support for
+ --enable-xxx configure option by adding ENABLE_{CLIBS DEPFILES}
+ where appropriate.
+
+ * General hackery to support alternate user-interface.
+ * breakpoint.c (mention, delete_breakpoint, enable_breakpoint,
+ disable_breakpoint): Call hooks for alternate user-interface.
+ * defs.h: Add declarations for alternate user-interface hooks.
+ * main.c (main): Add --nw (and --nowindows) options to disable
+ the GUI.
+ * (near call to command_loop): Call command_loop_hook if set.
+ * (fputs_unfiltered): Call fputs_unfiltered_hook if set.
+ * stack.c: Call print_frame_info_listing_hook if set.
+ * top.c (gdb_init): Initialize targets.c and utils.c prior to
+ other files to make sure that calls to error and warning will
+ work. Call init_ui_hook after everything else.
+ * utils.c (query): Call query_hook if set.
+ * (gdb_flush): Call flush_hook if set.
+ * Change _initialize_utils to initialize_utils cuz we don't use
+ automatic initialization of utils.c anymore.
+
+ * Support for TK GUI.
+ * Makefile.in: Add rule for gdbtk.o.
+ * configure.in: Add support for --enable-gdbtk.
+ * gdbtk.c: New file. Contains support routines for TK interface.
+ * gdbtk.tcl: New file. Implements GUI policy.
+
+ * remote.c: Get rid of #ifdef DONT_USE_REMOTE. It's no longer
+ necessary.
+
Thu Jul 28 14:52:01 1994 J.T. Conklin (jtc@phishhead.cygnus.com)
* Makefile.in (CC_FOR_TARGET, CXX_FOR_TARGET): Use newlib if it is
# If you have the Cygnus libraries installed,
# you can use 'CLIBS=$(INSTALLED_LIBS)' 'CDEPS='
INSTALLED_LIBS=-lbfd -lreadline $(TERMCAP) -lopcodes -lmmalloc \
- -liberty $(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS)
+ -liberty $(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) $(ENABLE_CLIBS)
CLIBS = $(BFD) $(READLINE) $(OPCODES) $(MMALLOC) \
- $(LIBIBERTY) $(TERMCAP) $(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS)
+ $(LIBIBERTY) $(TERMCAP) $(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) \
+ $(ENABLE_CLIBS)
CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) \
$(BFD) $(READLINE) $(OPCODES) $(MMALLOC) $(LIBIBERTY)
# variables analogous to SER_HARDWIRE which get defaulted in this
# Makefile.in
-DEPFILES = $(TDEPFILES) $(XDEPFILES) $(SER_HARDWIRE) $(NATDEPFILES) $(REMOTE_O)
+DEPFILES = $(TDEPFILES) $(XDEPFILES) $(SER_HARDWIRE) $(NATDEPFILES) $(REMOTE_O) \
+ $(ENABLE_DEPFILES)
SOURCES = $(SFILES) $(ALLDEPFILES) $(YYFILES)
# Don't include YYFILES (*.tab.c) because we already include *.y in SFILES,
fork-child.o: fork-child.c $(wait_h) $(defs_h) $(gdbcore_h) \
$(inferior_h) target.h terminal.h thread.h
+gdbtk.o: gdbtk.c $(defs_h) $(symtab_h) $(inferior_h) $(command_h) \
+ $(bfd_h) symfile.h objfiles.h target.h
+ $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/gdbtk.c \
+ -DGDBTK_FILENAME=\"$(libdir)/gdbtk.tcl\"
+
gdbtypes.o: gdbtypes.c $(bfd_h) complaints.h $(defs_h) $(expression_h) \
$(gdbtypes_h) language.h objfiles.h symfile.h $(symtab_h) target.h \
$(value_h)
{
int say_where = 0;
+ if (create_breakpoint_hook)
+ create_breakpoint_hook (b);
+
switch (b->type)
{
case bp_watchpoint:
register struct breakpoint *b;
register bpstat bs;
+ if (delete_breakpoint_hook)
+ delete_breakpoint_hook (bpt);
+
if (bpt->inserted)
remove_breakpoint (bpt);
int target_resources_ok, other_type_used;
struct value *mark;
+ if (enable_breakpoint_hook)
+ enable_breakpoint_hook (bpt);
+
if (bpt->type == bp_hardware_breakpoint)
{
int i;
if (bpt->type == bp_watchpoint_scope)
return;
+ if (disable_breakpoint_hook)
+ disable_breakpoint_hook (bpt);
+
bpt->enable = disabled;
breakpoints_changed ();
links="${links} nm.h"
fi
+# Make it possible to use the GUI without doing a full install
+if [ "${enable_gdbtk}" = "yes" ] ; then
+ files="${files} gdbtk.tcl"
+ links="${links} gdbtk.tcl"
+fi
+
# post-target:
case ${srcdir} in
mv -f Makefile.tem Makefile
fi
+if [ "${enable_gdbtk}" = "yes" ] ; then
+ sed -e '/# End of host and/i\
+\
+ENABLE_DEPFILES = gdbtk.o\
+ENABLE_CLIBS = -ltcl -ltk -lX11 -lm
+' < Makefile > Makefile.tem
+ mv -f Makefile.tem Makefile
+fi
+
sed -e '/^TM_FILE[ ]*=/s,^TM_FILE[ ]*=[ ]*,&config/'"${gdb_target_cpu}"'/,
/^XM_FILE[ ]*=/s,^XM_FILE[ ]*=[ ]*,&config/'"${gdb_host_cpu}"'/,
/^NAT_FILE[ ]*=/s,^NAT_FILE[ ]*=[ ]*,&config/'"${gdb_host_cpu}"'/,' <Makefile >Makefile.tmp
language_c, /* C */
language_cplus, /* C++ */
language_chill, /* Chill */
- language_m2 /* Modula-2 */
+ language_m2, /* Modula-2 */
+ language_asm /* Assembly language */
};
/* the cleanup list records things that have to be undone
extern void
print_prompt PARAMS ((void));
-extern int
-batch_mode PARAMS ((void));
-
extern int
input_from_terminal_p PARAMS ((void));
print_address_symbolic PARAMS ((CORE_ADDR, GDB_FILE *, int, char *));
extern void
-print_address_numeric PARAMS ((CORE_ADDR, GDB_FILE *));
+print_address_numeric PARAMS ((CORE_ADDR, int, GDB_FILE *));
extern void
print_address PARAMS ((CORE_ADDR, GDB_FILE *));
#define MAINTENANCE_CMDS 1
#endif
+/* Hooks for alternate command interfaces. */
+
+#ifdef __STDC__
+struct symtab;
+struct breakpoint;
+#endif
+
+void (*init_ui_hook) PARAMS ((void));
+void (*command_loop_hook) PARAMS ((void));
+void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer));
+void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s, int line,
+ int stopline, int noerror));
+int (*query_hook) PARAMS (());
+void (*flush_hook) PARAMS ((FILE *stream));
+void (*create_breakpoint_hook) PARAMS ((struct breakpoint *b));
+void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
+void (*enable_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
+void (*disable_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
+
+/* Inhibit window interface if non-zero. */
+
+extern int no_windows;
+
#endif /* !defined (DEFS_H) */
--- /dev/null
+/* TK interface routines.
+ Copyright 1994 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "command.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "target.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <varargs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/filio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/errno.h>
+#include <termios.h>
+#include <string.h>
+#include <tcl.h>
+#include <tk.h>
+
+/* Non-zero means that we're doing the gdbtk interface. */
+int gdbtk = 0;
+
+/* Non-zero means we are reloading breakpoints, etc from the
+ Gdbtk kernel, and we should suppress various messages */
+static int gdbtk_reloading = 0;
+
+/* Handle for TCL interpreter */
+static Tcl_Interp *interp = NULL;
+
+/* Handle for TK main window */
+static Tk_Window mainWindow = NULL;
+
+static void
+null_routine(arg)
+ int arg;
+{
+}
+
+\f
+/* This routine redirects the output of fputs_unfiltered so that
+ the user can see what's going on in his debugger window. */
+
+static void
+gdbtk_fputs (ptr)
+ const char *ptr;
+{
+ Tcl_VarEval (interp, "gdbtk_tcl_fputs ", "{", ptr, "}", NULL);
+}
+
+static void
+gdbtk_flush (stream)
+ FILE *stream;
+{
+ Tcl_VarEval (interp, "gdbtk_tcl_flush", NULL);
+}
+
+static int
+gdbtk_query (args)
+ va_list args;
+{
+ char *query;
+ char buf[200];
+ long val;
+
+ query = va_arg (args, char *);
+
+ vsprintf(buf, query, args);
+ Tcl_VarEval (interp, "gdbtk_tcl_query ", "{", buf, "}", NULL);
+
+ val = atol (interp->result);
+ return val;
+}
+\f
+static char *
+full_filename(symtab)
+ struct symtab *symtab;
+{
+ int pathlen;
+ char *filename;
+
+ if (!symtab)
+ return NULL;
+
+ if (symtab->fullname)
+ return savestring(symtab->fullname, strlen(symtab->fullname));
+
+ if (symtab->filename[0] == '/')
+ return savestring(symtab->filename, strlen(symtab->filename));
+
+ if (symtab->dirname)
+ pathlen = strlen(symtab->dirname);
+ else
+ pathlen = 0;
+ if (symtab->filename)
+ pathlen += strlen(symtab->filename);
+
+ filename = xmalloc(pathlen+1);
+
+ if (symtab->dirname)
+ strcpy(filename, symtab->dirname);
+ else
+ *filename = '\000';
+ if (symtab->filename)
+ strcat(filename, symtab->filename);
+
+ return filename;
+}
+\f
+static void
+breakpoint_notify(b, action)
+ struct breakpoint *b;
+ const char *action;
+{
+ struct symbol *sym;
+ char bpnum[50], line[50];
+ struct symtab_and_line sal;
+ char *filename;
+ int v;
+
+ if (b->type != bp_breakpoint)
+ return;
+
+ sal = find_pc_line (b->address, 0);
+
+ filename = full_filename (sal.symtab);
+
+ sprintf (bpnum, "%d", b->number);
+ sprintf (line, "%d", sal.line);
+
+ v = Tcl_VarEval (interp,
+ "gdbtk_tcl_breakpoint ",
+ action,
+ " ", bpnum,
+ " ", filename,
+ " ", line,
+ NULL);
+
+ if (v != TCL_OK)
+ {
+ gdbtk_fputs (interp->result);
+ gdbtk_fputs ("\n");
+ }
+
+ if (filename)
+ free (filename);
+}
+
+static void
+gdbtk_create_breakpoint(b)
+ struct breakpoint *b;
+{
+ breakpoint_notify(b, "create");
+}
+
+static void
+gdbtk_delete_breakpoint(b)
+ struct breakpoint *b;
+{
+ breakpoint_notify(b, "delete");
+}
+
+static void
+gdbtk_enable_breakpoint(b)
+ struct breakpoint *b;
+{
+ breakpoint_notify(b, "enable");
+}
+
+static void
+gdbtk_disable_breakpoint(b)
+ struct breakpoint *b;
+{
+ breakpoint_notify(b, "disable");
+}
+\f
+/* This implements the TCL command `gdb_loc', which returns a list consisting
+ of the source and line number associated with the current pc. */
+
+static int
+gdb_loc (clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char *argv[];
+{
+ char *filename;
+ char buf[100];
+ struct symtab_and_line sal;
+ char *funcname;
+
+ if (argc == 1)
+ {
+ struct frame_info *frame;
+ struct symbol *func;
+ CORE_ADDR pc;
+
+ frame = get_frame_info (selected_frame);
+ pc = frame ? frame->pc : stop_pc;
+ func = find_pc_function (pc);
+ funcname = func ? SYMBOL_NAME (func) : "";
+ sal = find_pc_line (pc, 0);
+ }
+ else if (argc == 2)
+ {
+ struct cleanup *old_chain;
+ struct symtabs_and_lines sals;
+
+ sals = decode_line_spec (argv[1], 1);
+
+ if (sals.nelts != 1)
+ {
+ Tcl_SetResult (interp, "Ambiguous line spec", TCL_STATIC);
+ free (sals.sals);
+ return TCL_ERROR;
+ }
+
+ sal = sals.sals[0];
+ free (sals.sals);
+ funcname = "*";
+ }
+ else
+ {
+ Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
+ return TCL_ERROR;
+ }
+
+ filename = full_filename (sal.symtab);
+
+ sprintf (buf, "%d", sal.line);
+
+ if (sal.symtab)
+ Tcl_AppendElement (interp, sal.symtab->filename);
+ else
+ Tcl_AppendElement (interp, "");
+ Tcl_AppendElement (interp, funcname);
+ Tcl_AppendElement (interp, filename);
+ Tcl_AppendElement (interp, buf); /* line number */
+
+ if (filename)
+ free(filename);
+
+ return TCL_OK;
+}
+\f
+static int
+gdb_cmd_stub (cmd)
+ char *cmd;
+{
+ execute_command (cmd, 1);
+
+ return 1; /* Indicate success */
+}
+
+/* This implements the TCL command `gdb_cmd', which sends it's argument into
+ the GDB command scanner. */
+
+static int
+gdb_cmd (clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char *argv[];
+{
+ int val;
+ struct cleanup *old_chain;
+
+ if (argc != 2)
+ {
+ Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
+ return TCL_ERROR;
+ }
+
+ old_chain = make_cleanup (null_routine, 0);
+
+ val = catch_errors (gdb_cmd_stub, argv[1], "", RETURN_MASK_ERROR);
+
+ bpstat_do_actions (&stop_bpstat);
+ do_cleanups (old_chain);
+
+ /* We could base the return value on val, but that would require most users
+ to use catch. Since GDB errors are already being handled elsewhere, I
+ see no reason to pass them up to the caller. */
+
+ return TCL_OK;
+}
+
+static int
+gdb_listfiles (clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char *argv[];
+{
+ int val;
+ struct objfile *objfile;
+ struct partial_symtab *psymtab;
+
+ ALL_PSYMTABS (objfile, psymtab)
+ Tcl_AppendElement (interp, psymtab->filename);
+
+ return TCL_OK;
+}
+\f
+static void
+tk_command (cmd, from_tty)
+ char *cmd;
+ int from_tty;
+{
+ Tcl_VarEval (interp, cmd, NULL);
+
+ gdbtk_fputs (interp->result);
+ gdbtk_fputs ("\n");
+}
+
+static void
+cleanup_init (ignored)
+ int ignored;
+{
+ if (mainWindow != NULL)
+ Tk_DestroyWindow (mainWindow);
+ mainWindow = NULL;
+
+ if (interp != NULL)
+ Tcl_DeleteInterp (interp);
+ interp = NULL;
+}
+
+static void
+gdbtk_init ()
+{
+ struct cleanup *old_chain;
+ char *gdbtk_filename;
+
+ old_chain = make_cleanup (cleanup_init, 0);
+
+ /* First init tcl and tk. */
+
+ interp = Tcl_CreateInterp ();
+
+ if (!interp)
+ error ("Tcl_CreateInterp failed");
+
+ mainWindow = Tk_CreateMainWindow (interp, NULL, "gdb", "Gdb");
+
+ if (!mainWindow)
+ return; /* DISPLAY probably not set */
+
+ if (Tcl_Init(interp) != TCL_OK)
+ error ("Tcl_Init failed: %s", interp->result);
+
+ if (Tk_Init(interp) != TCL_OK)
+ error ("Tk_Init failed: %s", interp->result);
+
+ Tcl_CreateCommand (interp, "gdb_cmd", gdb_cmd, NULL, NULL);
+ Tcl_CreateCommand (interp, "gdb_loc", gdb_loc, NULL, NULL);
+ Tcl_CreateCommand (interp, "gdb_listfiles", gdb_listfiles, NULL, NULL);
+
+ gdbtk_filename = getenv ("GDBTK_FILENAME");
+ if (gdbtk_filename)
+ {
+ if (Tcl_EvalFile (interp, gdbtk_filename) != TCL_OK)
+ error ("Failure reading %s: %s", gdbtk_filename, interp->result);
+ }
+ else
+ {
+ if (Tcl_EvalFile (interp, "gdbtk.tcl") != TCL_OK)
+ {
+ Tcl_ResetResult (interp);
+ if (Tcl_EvalFile (interp, GDBTK_FILENAME) != TCL_OK)
+ error ("Failure reading %s: %s", GDBTK_FILENAME, interp->result);
+ }
+ }
+
+ command_loop_hook = Tk_MainLoop;
+ fputs_unfiltered_hook = gdbtk_fputs;
+ print_frame_info_listing_hook = null_routine;
+ query_hook = gdbtk_query;
+ flush_hook = gdbtk_flush;
+ create_breakpoint_hook = gdbtk_create_breakpoint;
+ delete_breakpoint_hook = gdbtk_delete_breakpoint;
+ enable_breakpoint_hook = gdbtk_enable_breakpoint;
+ disable_breakpoint_hook = gdbtk_disable_breakpoint;
+
+ discard_cleanups (old_chain);
+
+ add_com ("tk", class_obscure, tk_command,
+ "Send a command directly into tk.");
+}
+
+/* Come here during initialze_all_files () */
+
+void
+_initialize_gdbtk ()
+{
+ if (no_windows)
+ return;
+
+ /* Tell the rest of the world that Gdbtk is now set up. */
+
+ init_ui_hook = gdbtk_init;
+}
--- /dev/null
+# GDB GUI setup
+
+set cfile Blank
+set wins($cfile) .text
+set current_label {}
+set screen_height 0
+set screen_top 0
+set screen_bot 0
+
+proc test {} {
+ update_listing {termcap.c foo /etc/termcap 200}
+}
+
+proc echo string {puts stdout $string}
+
+proc gdbtk_tcl_fputs {arg} {
+ .command.text insert end "$arg"
+ .command.text yview -pickplace end
+}
+
+proc gdbtk_tcl_flush {} {update idletasks}
+
+proc gdbtk_tcl_query {message} {
+ tk_dialog .query "gdb : query" "$message" {} 1 "No" "Yes"
+ }
+
+if [info exists env(EDITOR)] then {
+ set editor $env(EDITOR)
+ } else {
+ set editor emacs
+}
+
+proc gdbtk_tcl_start_variable_annotation {valaddr ref_type stor_cl cum_expr field type_cast} {
+ echo "gdbtk_tcl_start_variable_annotation $valaddr $ref_type $stor_cl $cum_expr $field $type_cast"
+}
+
+proc gdbtk_tcl_end_variable_annotation {} {
+ echo gdbtk_tcl_end_variable_annotation
+}
+
+proc insert_breakpoint_tag {win line} {
+ $win configure -state normal
+ $win delete $line.0
+ $win insert $line.0 "B"
+ $win tag add $line $line.0
+ $win tag bind $line <1> {
+# echo "tag %W %X %Y %x"
+# echo "tag names [$wins($cfile) tag names]"
+ }
+
+ $win configure -state disabled
+}
+
+proc delete_breakpoint_tag {win line} {
+ $win configure -state normal
+ $win delete $line.0
+ $win insert $line.0 " "
+ $win tag delete $line
+ $win configure -state disabled
+}
+
+# Callback from GDB to notify us of breakpoint creation.
+
+proc create_breakpoint {bpnum file line} {
+ global wins
+ global breakpoint_file
+ global breakpoint_line
+
+# Record breakpoint locations
+
+ set breakpoint_file($bpnum) $file
+ set breakpoint_line($bpnum) $line
+
+# If there isn't a window for this file, don't try to update it
+
+ if [info exists wins($file)] {
+ insert_breakpoint_tag $wins($file) $line
+ }
+}
+
+proc delete_breakpoint {bpnum file line} {
+ global wins
+ global breakpoint_file
+ global breakpoint_line
+
+# Save line number for later
+
+ set line $breakpoint_line($bpnum)
+
+# Reset breakpoint annotation info
+
+ unset breakpoint_file($bpnum)
+ unset breakpoint_line($bpnum)
+
+# If there isn't a window for this file, don't try to update it
+
+ if [info exists wins($file)] {
+ delete_breakpoint_tag $wins($file) $line
+ }
+}
+
+# This is a callback from C code to notify us of breakpoint changes. ACTION
+# can be one of create, delete, enable, or disable.
+
+proc gdbtk_tcl_breakpoint {action bpnum file line} {
+ ${action}_breakpoint $bpnum $file $line
+}
+
+# Create the popup listing window menu
+
+menu .breakpoint -cursor hand2
+.breakpoint add command -label Break
+.breakpoint add separator
+.breakpoint add command -label "Edit" -command {exec $editor +$selected_line $selected_file &}
+.breakpoint add command -label "Set breakpoint" -command {gdb_cmd "break $selected_file:$selected_line"}
+#.breakpoint add command -label "Clear breakpoint" -command {echo "Clear"}
+#.breakpoint add command -label "Enable breakpoint" -command {echo "Enable"}
+#.breakpoint add command -label "Disable breakpoint" -command {echo "Disable"}
+
+# Come here when button is released in the popup menu
+
+bind .breakpoint <Any-ButtonRelease-1> {
+ global selected_win
+
+# First, remove the menu, and release the pointer
+
+ .breakpoint unpost
+ grab release .breakpoint
+
+# Unhighlight the selected line
+
+ $selected_win tag delete breaktag
+# echo "after deleting $selected_win [$selected_win tag names]"
+# echo "grab [grab current]"
+
+# Actually invoke the menubutton here!
+
+ tk_invokeMenu %W
+# destroy .breakpoint
+ grab release $selected_win
+}
+
+# Button 1 has been pressed in a listing window. Pop up a menu.
+
+proc breakpoint_menu {win x y xrel yrel} {
+ global wins
+ global win_to_file
+ global file_to_debug_file
+ global highlight
+ global selected_line
+ global selected_file
+ global selected_win
+
+ grab $win
+
+# echo "bpm grab current [grab current]"
+
+# Map TK window name back to file name.
+
+ set file $win_to_file($win)
+
+ set pos [$win index @$xrel,$yrel]
+
+# Record selected file and line for menu button actions
+
+ set selected_file $file_to_debug_file($file)
+ set selected_line [lindex [split $pos .] 0]
+ set selected_win $win
+
+# Highlight the selected line
+
+ eval $win tag config breaktag $highlight
+ $win tag add breaktag "$pos linestart" "$pos linestart + 1l"
+
+# Post the menu near the pointer, (and grab it)
+
+ .breakpoint post [expr $x-[winfo width .breakpoint]/2] [expr $y-10]
+ grab .breakpoint
+# echo "after grab [grab current]"
+}
+
+proc do_nothing {} {}
+
+proc create_file_win {filename} {
+ global breakpoint_file
+ global breakpoint_line
+
+ regsub -all {\.|/} $filename {} temp
+ set win .text$temp
+ text $win -height 25 -width 80 -relief raised -borderwidth 2 -yscrollcommand textscrollproc -setgrid true -cursor hand2
+ bind $win <Enter> {focus %W}
+# bind $win <1> {breakpoint_menu %W %X %Y %x %y}
+ bind $win <B1-Motion> do_nothing
+ bind $win n {gdb_cmd next ; update_ptr}
+ bind $win s {gdb_cmd step ; update_ptr}
+ bind $win c {gdb_cmd continue ; update_ptr}
+ bind $win f {gdb_cmd finish ; update_ptr}
+ bind $win u {gdb_cmd up ; update_ptr}
+ bind $win d {gdb_cmd down ; update_ptr}
+ set fh [open $filename]
+ $win delete 0.0 end
+ $win insert 0.0 [read $fh]
+ close $fh
+ set numlines [$win index end]
+ set numlines [lindex [split $numlines .] 0]
+ for {set i 1} {$i <= $numlines} {incr i} {
+ $win insert $i.0 [format " %4d " $i]
+ }
+
+ $win tag add wholebuf 0.0 end
+ $win tag bind wholebuf <1> {breakpoint_menu %W %X %Y %x %y}
+ foreach bpnum [array names breakpoint_file] {
+ if {$breakpoint_file($bpnum) == $filename} {
+ insert_breakpoint_tag $win $breakpoint_line($bpnum)
+ }
+ }
+
+ $win configure -state disabled
+ return $win
+}
+
+proc update_listing {linespec} {
+ global pointers
+ global screen_height
+ global screen_top
+ global screen_bot
+ global wins cfile
+ global current_label
+ global win_to_file
+ global file_to_debug_file
+
+ set line [lindex $linespec 3]
+ set filename [lindex $linespec 2]
+ set funcname [lindex $linespec 1]
+ set debug_file [lindex $linespec 0]
+
+ if {$filename == ""} {set filename Blank}
+
+ if {$filename != $cfile} then {
+ pack forget $wins($cfile)
+ set cfile $filename
+ if ![info exists wins($cfile)] then {
+ set wins($cfile) [create_file_win $cfile]
+ set win_to_file($wins($cfile)) $cfile
+ set file_to_debug_file($cfile) $debug_file
+ set pointers($cfile) 1.1
+ }
+
+ pack $wins($cfile) -side left -expand yes -in .listing -fill both -after .label
+ $wins($cfile) yview [expr $line - $screen_height / 2]
+ }
+
+ if {$current_label != "$filename.$funcname"} then {
+ set tail [expr [string last / $filename] + 1]
+ .label configure -text "[string range $filename $tail end] : ${funcname}()"
+ set current_label $filename.$funcname
+ }
+
+ if [info exists pointers($cfile)] then {
+ $wins($cfile) configure -state normal
+ set pointer_pos $pointers($cfile)
+ $wins($cfile) configure -state normal
+ $wins($cfile) delete $pointer_pos
+ $wins($cfile) insert $pointer_pos " "
+
+ set pointer_pos [$wins($cfile) index $line.1]
+ set pointers($cfile) $pointer_pos
+
+ $wins($cfile) delete $pointer_pos
+ $wins($cfile) insert $pointer_pos "\xbb"
+
+ if {$line < $screen_top + 1
+ || $line > $screen_bot} then {
+ $wins($cfile) yview [expr $line - $screen_height / 2]
+ }
+
+ $wins($cfile) configure -state disabled
+ }
+}
+
+proc update_ptr {} {update_listing [gdb_loc]}
+
+# Setup listing window
+
+frame .listing
+
+wm minsize . 1 1
+
+label .label -text "*No file*" -borderwidth 2 -relief raised
+text $wins($cfile) -height 25 -width 80 -relief raised -borderwidth 2 -yscrollcommand textscrollproc -setgrid true -cursor hand2
+scrollbar .scroll -orient vertical -command {$wins($cfile) yview}
+
+if {[tk colormodel .text] == "color"} {
+ set highlight "-background red2 -borderwidth 2 -relief sunk"
+} else {
+ set fg [lindex [.text config -foreground] 4]
+ set bg [lindex [.text config -background] 4]
+ set highlight "-foreground $bg -background $fg -borderwidth 0"
+}
+
+proc textscrollproc {args} {global screen_height screen_top screen_bot
+ eval ".scroll set $args"
+ set screen_height [lindex $args 1]
+ set screen_top [lindex $args 2]
+ set screen_bot [lindex $args 3]}
+
+$wins($cfile) insert 0.0 " This page intentionally left blank."
+$wins($cfile) configure -state disabled
+
+pack .label -side bottom -fill x -in .listing
+pack $wins($cfile) -side left -expand yes -in .listing -fill both
+pack .scroll -side left -fill y -in .listing
+
+button .start -text Start -command \
+ {gdb_cmd {break main}
+ gdb_cmd {enable delete $bpnum}
+ gdb_cmd run
+ update_ptr }
+button .step -text Step -command {gdb_cmd step ; update_ptr}
+button .next -text Next -command {gdb_cmd next ; update_ptr}
+button .continue -text Continue -command {gdb_cmd continue ; update_ptr}
+button .finish -text Finish -command {gdb_cmd finish ; update_ptr}
+#button .test -text Test -command {echo [info var]}
+button .exit -text Exit -command {gdb_cmd quit}
+button .up -text Up -command {gdb_cmd up ; update_ptr}
+button .down -text Down -command {gdb_cmd down ; update_ptr}
+button .bottom -text "Bottom" -command {gdb_cmd {frame 0} ; update_ptr}
+
+proc files_command {} {
+ toplevel .files_window
+
+ wm minsize .files_window 1 1
+# wm overrideredirect .files_window true
+ listbox .files_window.list -geometry 30x20 -setgrid true
+ button .files_window.close -text Close -command {destroy .files_window}
+ tk_listboxSingleSelect .files_window.list
+ eval .files_window.list insert 0 [lsort [gdb_listfiles]]
+ pack .files_window.list -side top -fill both -expand yes
+ pack .files_window.close -side bottom -fill x -expand no -anchor s
+ bind .files_window.list <Any-ButtonRelease-1> {
+ set file [%W get [%W curselection]]
+ gdb_cmd "list $file:1,0"
+ update_listing [gdb_loc $file:1]
+ destroy .files_window}
+}
+
+button .files -text Files -command files_command
+
+pack .listing -side bottom -fill both -expand yes
+#pack .test -side bottom -fill x
+pack .start .step .next .continue .finish .up .down .bottom .files .exit -side left
+toplevel .command
+
+# Setup command window
+
+label .command.label -text "* Command Buffer *" -borderwidth 2 -relief raised
+text .command.text -height 25 -width 80 -relief raised -borderwidth 2 -setgrid true -cursor hand2
+
+pack .command.label -side top -fill x
+pack .command.text -side top -expand yes -fill both
+
+set command_line {}
+
+gdb_cmd {set language c}
+gdb_cmd {set height 0}
+gdb_cmd {set width 0}
+
+bind .command.text <Any-Key> {
+ global command_line
+
+ %W insert end %A
+ %W yview -pickplace end
+ append command_line %A
+ }
+bind .command.text <Key-Return> {
+ global command_line
+
+ %W insert end \n
+ %W yview -pickplace end
+ gdb_cmd $command_line
+ set command_line {}
+ update_ptr
+ %W insert end "(gdb) "
+ %W yview -pickplace end
+ }
+bind .command.text <Enter> {focus %W}
+bind .command.text <Delete> {delete_char %W}
+bind .command.text <BackSpace> {delete_char %W}
+proc delete_char {win} {
+ global command_line
+
+ tk_textBackspace $win
+ $win yview -pickplace insert
+ set tmp [expr [string length $command_line] - 2]
+ set command_line [string range $command_line 0 $tmp]
+}
+
+wm minsize .command 1 1
+
{"tty", required_argument, 0, 't'},
{"baud", required_argument, 0, 'b'},
{"b", required_argument, 0, 'b'},
+ {"nw", no_argument, &no_windows, 1},
+ {"nowindows", no_argument, &no_windows, 1},
/* Allow machine descriptions to add more options... */
#ifdef ADDITIONAL_OPTIONS
ADDITIONAL_OPTIONS
-b BAUDRATE Set serial port baud rate used for remote debugging.\n\
--mapped Use mapped symbol files if supported on this system.\n\
--readnow Fully read symbol files on first access.\n\
+ --nw Do not use a window interface.\n\
", gdb_stdout);
/* start-sanitize-mpw */
#endif /* MPW_C */
stat (gdbinit, &cwdbuf); /* We'll only need this if
homedir was set. */
}
-
+
/* Now perform all the actions indicated by the arguments. */
if (cdarg != NULL)
{
if (!SET_TOP_LEVEL ())
{
do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */
-/* start-sanitize-mpw */
-#ifdef MPW
- /* If we're being a Mac application, go into a Mac-specific
- event-handling loop instead. We still want to be inside
- the outer loop, because that will catch longjmps resulting
- from some command executions. */
- if (mac_app)
- mac_command_loop ();
+ /* GUIs generally have their own command loop, mainloop, or whatever.
+ This is a good place to gain control because many error
+ conditions will end up here via longjmp(). */
+ if (command_loop_hook)
+ command_loop_hook ();
else
-#endif /* MPW */
-/* end-sanitize-mpw */
- command_loop ();
+ command_loop ();
quit_command ((char *)0, instream == stdin);
}
}
const char *linebuffer;
FILE *stream;
{
+ if (fputs_unfiltered_hook)
+ {
+ fputs_unfiltered_hook (linebuffer);
+ return;
+ }
+
fputs (linebuffer, stream);
}
general set QXXXX=yyyy Set value of XXXX to yyyy.
query sect offs qOffsets Get section offsets. Reply is
Text=xxx;Data=yyy;Bss=zzz
+ console output Otext Send text to stdout. Only comes from
+ remote target.
Responses can be run-length encoded to save space. A '*' means that
the next two characters are hex digits giving a repeat count which
#include "dcache.h"
-#if !defined(DONT_USE_REMOTE)
#ifdef USG
#include <sys/types.h>
#endif
remote_send PARAMS ((char *buf));
static int
-readchar PARAMS ((void));
+readchar PARAMS ((int timeout));
static int remote_wait PARAMS ((int pid, struct target_waitstatus *status));
Unless this is going though some terminal server or multiplexer or
other form of hairy serial connection, I would think 2 seconds would
be plenty. */
-static int timeout = 2;
+static int remote_timeout = 2;
#if 0
int icache;
return a - 'a' + 10;
else
error ("Reply contains invalid hex digit");
- return -1;
}
/* Convert number NIB to a hex digit. */
getpkt ((char *) buf, 1);
signal (SIGINT, ofunc);
- if (buf[0] == 'E')
- warning ("Remote failure reply: %s", buf);
- else if (buf[0] == 'T')
+ switch (buf[0])
{
- int i;
- long regno;
- char regs[MAX_REGISTER_RAW_SIZE];
+ case 'E': /* Error of some sort */
+ warning ("Remote failure reply: %s", buf);
+ continue;
+ case 'T': /* Status with PC, SP, FP, ... */
+ {
+ int i;
+ long regno;
+ char regs[MAX_REGISTER_RAW_SIZE];
- /* Expedited reply, containing Signal, {regno, reg} repeat */
- /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
- ss = signal number
- n... = register number
- r... = register contents
- */
+ /* Expedited reply, containing Signal, {regno, reg} repeat */
+ /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
+ ss = signal number
+ n... = register number
+ r... = register contents
+ */
- p = &buf[3]; /* after Txx */
+ p = &buf[3]; /* after Txx */
- while (*p)
- {
- unsigned char *p1;
+ while (*p)
+ {
+ unsigned char *p1;
- regno = strtol (p, &p1, 16); /* Read the register number */
+ regno = strtol (p, &p1, 16); /* Read the register number */
- if (p1 == p)
- warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
- p1, buf);
+ if (p1 == p)
+ warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
+ p1, buf);
- p = p1;
+ p = p1;
- if (*p++ != ':')
- warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
- p, buf);
+ if (*p++ != ':')
+ warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
+ p, buf);
- if (regno >= NUM_REGS)
- warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
- regno, p, buf);
+ if (regno >= NUM_REGS)
+ warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
+ regno, p, buf);
- for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
- {
- if (p[0] == 0 || p[1] == 0)
- warning ("Remote reply is too short: %s", buf);
- regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
- p += 2;
- }
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ warning ("Remote reply is too short: %s", buf);
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
- if (*p++ != ';')
- warning ("Remote register badly formatted: %s", buf);
+ if (*p++ != ';')
+ warning ("Remote register badly formatted: %s", buf);
+
+ supply_register (regno, regs);
+ }
+ }
+ /* fall through */
+ case 'S': /* Old style status, just signal only */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
- supply_register (regno, regs);
- }
- break;
- }
- else if (buf[0] == 'W')
- {
- /* The remote process exited. */
- status->kind = TARGET_WAITKIND_EXITED;
- status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
return 0;
+ case 'W': /* Target exited */
+ {
+ /* The remote process exited. */
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
+ return 0;
+ }
+ case 'O': /* Console output */
+ fputs_filtered (buf + 1, gdb_stdout);
+ continue;
+ default:
+ warning ("Invalid remote reply: %s", buf);
+ continue;
}
- else if (buf[0] == 'S')
- break;
- else
- warning ("Invalid remote reply: %s", buf);
}
-
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = (enum target_signal)
- (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
-
return 0;
}
/* Read a single character from the remote end, masking it down to 7 bits. */
static int
-readchar ()
+readchar (timeout)
+ int timeout;
{
int ch;
ch = SERIAL_READCHAR (remote_desc, timeout);
- if (ch < 0)
- return ch;
-
- return ch & 0x7f;
+ switch (ch)
+ {
+ case SERIAL_EOF:
+ error ("Remote connection closed");
+ case SERIAL_ERROR:
+ perror_with_name ("Remote communication error");
+ case SERIAL_TIMEOUT:
+ return ch;
+ default:
+ return ch & 0x7f;
+ }
}
/* Send the command in BUF to the remote machine,
/* read until either a timeout occurs (-2) or '+' is read */
while (1)
{
- ch = readchar ();
+ ch = readchar (remote_timeout);
if (remote_debug)
{
{
case '+':
case SERIAL_TIMEOUT:
- case SERIAL_ERROR:
- case SERIAL_EOF:
case '$':
if (started_error_output)
{
return;
case SERIAL_TIMEOUT:
break; /* Retransmit buffer */
- case SERIAL_ERROR:
- perror_with_name ("putpkt: couldn't read ACK");
- case SERIAL_EOF:
- error ("putpkt: EOF while trying to read ACK");
case '$':
{
unsigned char junkbuf[PBUFSIZ];
}
}
+/* Come here after finding the start of the frame. Collect the rest into BUF,
+ verifying the checksum, length, and handling run-length compression.
+ Returns 0 on any error, 1 on success. */
+
+static int
+read_frame (buf)
+ char *buf;
+{
+ unsigned char csum;
+ char *bp;
+ int c;
+
+ csum = 0;
+ bp = buf;
+
+ while (1)
+ {
+ c = readchar (remote_timeout);
+
+ switch (c)
+ {
+ case SERIAL_TIMEOUT:
+ if (remote_debug)
+ puts_filtered ("Timeout in mid-packet, retrying\n");
+ return 0;
+ case '$':
+ if (remote_debug)
+ puts_filtered ("Saw new packet start in middle of old one\n");
+ return 0; /* Start a new packet, count retries */
+ case '#':
+ {
+ unsigned char pktcsum;
+
+ *bp = '\000';
+
+ pktcsum = fromhex (readchar (remote_timeout)) << 4
+ | fromhex (readchar (remote_timeout));
+
+ if (csum == pktcsum)
+ return 1;
+
+ printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ pktcsum, csum);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ }
+ case '*': /* Run length encoding */
+ c = readchar (remote_timeout);
+ csum += c;
+ c = c - ' ' + 3; /* Compute repeat count */
+
+ if (bp + c - 1 < buf + PBUFSIZ - 1)
+ {
+ memset (bp, *(bp - 1), c);
+ bp += c;
+ continue;
+ }
+
+ *bp = '\0';
+ printf_filtered ("Repeat count %d too large for buffer: ", c);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ default:
+ if (bp < buf + PBUFSIZ - 1)
+ {
+ *bp++ = c;
+ csum += c;
+ continue;
+ }
+
+ *bp = '\0';
+ puts_filtered ("Remote packet too long: ");
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ }
+ }
+}
+
/* Read a packet from the remote machine, with error checking,
and store it in BUF. BUF is expected to be of size PBUFSIZ.
If FOREVER, wait forever rather than timing out; this is used
while the target is executing user code. */
static void
-getpkt (retbuf, forever)
- char *retbuf;
+getpkt (buf, forever)
+ char *buf;
int forever;
{
char *bp;
- unsigned char csum;
- int c = 0;
- unsigned char c1, c2;
- int retries = 0;
- char buf[PBUFSIZ];
+ int c;
+ int tries;
+ int timeout;
+ int val;
-#define MAX_RETRIES 10
+ if (forever)
+ timeout = -1;
+ else
+ timeout = remote_timeout;
- while (1)
- {
-#if 0
- /* This is wrong. If doing a long backtrace, the user should be
- able to get out time next we call QUIT, without anything as violent
- as interrupt_query. If we want to provide a way out of here
- without getting to the next QUIT, it should be based on hitting
- ^C twice as in remote_wait. */
- if (quit_flag)
- {
- quit_flag = 0;
- interrupt_query ();
- }
-#endif
+#define MAX_TRIES 10
+ for (tries = 1; tries <= MAX_TRIES; tries++)
+ {
/* This can loop forever if the remote side sends us characters
continuously, but if it pauses, we'll get a zero from readchar
because of timeout. Then we'll count that as a retry. */
- c = readchar();
- if (c > 0 && c != '$')
- continue;
+ /* Note that we will only wait forever prior to the start of a packet.
+ After that, we expect characters to arrive at a brisk pace. They
+ should show up within remote_timeout intervals. */
- if (c == SERIAL_TIMEOUT)
+ do
{
- if (forever)
- continue;
- if (remote_debug)
- puts_filtered ("Timed out.\n");
- goto whole;
- }
-
- if (c == SERIAL_EOF)
- error ("Remote connection closed");
- if (c == SERIAL_ERROR)
- perror_with_name ("Remote communication error");
+ c = readchar (timeout);
- /* Force csum to be zero here because of possible error retry. */
- csum = 0;
- bp = buf;
-
- while (1)
- {
- c = readchar ();
if (c == SERIAL_TIMEOUT)
{
if (remote_debug)
- puts_filtered ("Timeout in mid-packet, retrying\n");
- goto whole; /* Start a new packet, count retries */
- }
- if (c == '$')
- {
- if (remote_debug)
- puts_filtered ("Saw new packet start in middle of old one\n");
- goto whole; /* Start a new packet, count retries */
+ puts_filtered ("Timed out.\n");
+ goto retry;
}
- if (c == '#')
- break;
- if (bp >= buf+PBUFSIZ-1)
- {
- *bp = '\0';
- puts_filtered ("Remote packet too long: ");
- puts_filtered (buf);
- puts_filtered ("\n");
- goto whole;
- }
- *bp++ = c;
- csum += c;
}
- *bp = 0;
+ while (c != '$');
- c1 = fromhex (readchar ());
- c2 = fromhex (readchar ());
- if ((csum & 0xff) == (c1 << 4) + c2)
- break;
- printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
- (c1 << 4) + c2, csum & 0xff);
- puts_filtered (buf);
- puts_filtered ("\n");
+ /* We've found the start of a packet, now collect the data. */
- /* Try the whole thing again. */
-whole:
- if (++retries < MAX_RETRIES)
- {
- SERIAL_WRITE (remote_desc, "-", 1);
- }
- else
+ val = read_frame (buf);
+
+ if (val == 1)
{
- printf_unfiltered ("Ignoring packet error, continuing...\n");
- break;
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stderr, "Packet received: %s\n", buf);
+ SERIAL_WRITE (remote_desc, "+", 1);
+ return;
}
+
+ /* Try the whole thing again. */
+retry:
+ SERIAL_WRITE (remote_desc, "-", 1);
}
- /* Deal with run-length encoding. */
- {
- char *src = buf;
- char *dest = retbuf;
- int i;
- int repeat;
- do {
- if (*src == '*')
- {
- if (src[1] == '\0' || src[2] == '\0')
- {
- if (remote_debug)
- puts_filtered ("Packet too short, retrying\n");
- goto whole;
- }
- repeat = (fromhex (src[1]) << 4) + fromhex (src[2]);
- for (i = 0; i < repeat; ++i)
- {
- *dest++ = src[-1];
- }
- src += 2;
- }
- else
- {
- *dest++ = *src;
- }
- } while (*src++ != '\0');
- }
+ /* We have tried hard enough, and just can't receive the packet. Give up. */
+ printf_unfiltered ("Ignoring packet error, continuing...\n");
SERIAL_WRITE (remote_desc, "+", 1);
-
- if (remote_debug)
- fprintf_unfiltered (gdb_stderr,"Packet received: %s\n", buf);
}
\f
static void
NULL, /* sections_end */
OPS_MAGIC /* to_magic */
};
-#endif /* Use remote. */
void
_initialize_remote ()
{
-#if !defined(DONT_USE_REMOTE)
add_target (&remote_ops);
-#endif
}
char gdbinit[] = GDBINIT_FILENAME;
int inhibit_gdbinit = 0;
+/* Disable windows if non-zero */
+
+int no_windows = 0;
+
/* Version number of GDB, as a string. */
extern char *version;
current_directory = gdb_dirbuf;
init_cmd_lists (); /* This needs to be done first */
+ initialize_targets (); /* Setup target_terminal macros for utils.c */
+ initialize_utils (); /* Make errors and warnings possible */
initialize_all_files ();
init_main (); /* But that omits this file! Do it now */
init_signals ();
or implicitly set by reading an executable during startup. */
set_language (language_c);
expected_language = current_language; /* don't warn about the change. */
+
+ if (init_ui_hook)
+ init_ui_hook ();
}
void