mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-28 22:40:24 +00:00
* 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:
parent
b98612f1fd
commit
754e5da26e
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 ();
|
||||
|
@ -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
|
||||
|
31
gdb/defs.h
31
gdb/defs.h
@ -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
424
gdb/gdbtk.c
Normal 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
399
gdb/gdbtk.tcl
Normal 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
|
||||
|
28
gdb/main.c
28
gdb/main.c
@ -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);
|
||||
}
|
||||
|
386
gdb/remote.c
386
gdb/remote.c
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user