* 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.
This commit is contained in:
Stu Grossman 1994-07-28 22:07:02 +00:00
parent b98612f1fd
commit 754e5da26e
10 changed files with 1142 additions and 207 deletions

View File

@ -1,3 +1,35 @@
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

View File

@ -169,9 +169,10 @@ REGEX1 = regex.o
# 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)
@ -454,7 +455,8 @@ TARDIRS = doc gdbserver sparclite
# 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,
@ -1204,6 +1206,11 @@ findvar.o: findvar.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h
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)

View File

@ -2149,6 +2149,9 @@ mention (b)
{
int say_where = 0;
if (create_breakpoint_hook)
create_breakpoint_hook (b);
switch (b->type)
{
case bp_watchpoint:
@ -3181,6 +3184,9 @@ delete_breakpoint (bpt)
register struct breakpoint *b;
register bpstat bs;
if (delete_breakpoint_hook)
delete_breakpoint_hook (bpt);
if (bpt->inserted)
remove_breakpoint (bpt);
@ -3539,6 +3545,9 @@ enable_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;
@ -3644,6 +3653,9 @@ disable_breakpoint (bpt)
if (bpt->type == bp_watchpoint_scope)
return;
if (disable_breakpoint_hook)
disable_breakpoint_hook (bpt);
bpt->enable = disabled;
breakpoints_changed ();

View File

@ -397,6 +397,12 @@ else
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
@ -413,6 +419,15 @@ if [ "${nativefile}" = "" ] ; then
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

View File

@ -92,7 +92,8 @@ enum language
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
@ -342,9 +343,6 @@ command_line_input PARAMS ((char *, int, char *));
extern void
print_prompt PARAMS ((void));
extern int
batch_mode PARAMS ((void));
extern int
input_from_terminal_p PARAMS ((void));
@ -357,7 +355,7 @@ extern 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 *));
@ -941,4 +939,27 @@ push_word PARAMS ((CORE_ADDR, unsigned LONGEST));
#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) */

424
gdb/gdbtk.c Normal file
View File

@ -0,0 +1,424 @@
/* 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;
{
}
/* 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;
}
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;
}
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");
}
/* 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;
}
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;
}
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;
}

399
gdb/gdbtk.tcl Normal file
View File

@ -0,0 +1,399 @@
# 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

View File

@ -174,6 +174,8 @@ main (argc, argv)
{"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
@ -350,6 +352,7 @@ Options:\n\
-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 */
@ -410,7 +413,7 @@ GDB manual (available as on-line info or a printed manual).\n", gdb_stdout);
stat (gdbinit, &cwdbuf); /* We'll only need this if
homedir was set. */
}
/* Now perform all the actions indicated by the arguments. */
if (cdarg != NULL)
{
@ -526,18 +529,13 @@ GDB manual (available as on-line info or a printed manual).\n", gdb_stdout);
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);
}
}
@ -570,5 +568,11 @@ fputs_unfiltered (linebuffer, stream)
const char *linebuffer;
FILE *stream;
{
if (fputs_unfiltered_hook)
{
fputs_unfiltered_hook (linebuffer);
return;
}
fputs (linebuffer, stream);
}

View File

@ -122,6 +122,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
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
@ -145,7 +147,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "dcache.h"
#if !defined(DONT_USE_REMOTE)
#ifdef USG
#include <sys/types.h>
#endif
@ -199,7 +200,7 @@ static void
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));
@ -227,7 +228,7 @@ extern struct target_ops remote_ops; /* Forward decl */
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;
@ -448,7 +449,6 @@ fromhex (a)
return a - 'a' + 10;
else
error ("Reply contains invalid hex digit");
return -1;
}
/* Convert number NIB to a hex digit. */
@ -558,75 +558,82 @@ remote_wait (pid, status)
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;
}
@ -1039,16 +1046,24 @@ remote_files_info (ignore)
/* 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,
@ -1117,7 +1132,7 @@ putpkt (buf)
/* read until either a timeout occurs (-2) or '+' is read */
while (1)
{
ch = readchar ();
ch = readchar (remote_timeout);
if (remote_debug)
{
@ -1125,8 +1140,6 @@ putpkt (buf)
{
case '+':
case SERIAL_TIMEOUT:
case SERIAL_ERROR:
case SERIAL_EOF:
case '$':
if (started_error_output)
{
@ -1144,10 +1157,6 @@ putpkt (buf)
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];
@ -1187,151 +1196,157 @@ putpkt (buf)
}
}
/* 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)
#define MAX_TRIES 10
for (tries = 1; tries <= MAX_TRIES; tries++)
{
#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
/* 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;
}
c = readchar (timeout);
if (c == SERIAL_EOF)
error ("Remote connection closed");
if (c == SERIAL_ERROR)
perror_with_name ("Remote communication error");
/* 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. */
val = read_frame (buf);
if (val == 1)
{
if (remote_debug)
fprintf_unfiltered (gdb_stderr, "Packet received: %s\n", buf);
SERIAL_WRITE (remote_desc, "+", 1);
return;
}
/* Try the whole thing again. */
whole:
if (++retries < MAX_RETRIES)
{
SERIAL_WRITE (remote_desc, "-", 1);
}
else
{
printf_unfiltered ("Ignoring packet error, continuing...\n");
break;
}
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);
}
static void
@ -1443,12 +1458,9 @@ Specify the serial device it is connected to (e.g. /dev/ttya).", /* to_doc */
NULL, /* sections_end */
OPS_MAGIC /* to_magic */
};
#endif /* Use remote. */
void
_initialize_remote ()
{
#if !defined(DONT_USE_REMOTE)
add_target (&remote_ops);
#endif
}

View File

@ -146,6 +146,10 @@ source_cleanup PARAMS ((FILE *));
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;
@ -488,6 +492,8 @@ gdb_init ()
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 ();
@ -499,6 +505,9 @@ gdb_init ()
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