* monitor.c: Turn on caching.
(monitor_printf): If a ^C was sent, don't expect to see its
echo.
(monitor_open): Enable caching.
(monitor_resume, monitor_load): Flush cache.
(monitor_xfer_memory): Call cache routine.
(monitor_dump_regs): New.
(monitor_fetch_registers): If monitor_dump_regs available
then use it.
(monitor_load): Don't ref exec_bfd if it's NULL.
(monitor_load_srec): Use new monitor_make_srec calling convention.
(monitor_make_srec): Rewrite to cope with two, three and four byte
addresses.
* remote-hms.c (hms_cmds): Initialze end-of-command delim.
* dcache.h, dcache.h: Rewritten.
* remote.c: Reenable caching.
(getpkt): Reduce MAX_TRIES to 3.
(remote_xfer_memory): Use dcache_xfer_memory.
* defs.h (error_hook): New.
* top.c (error_hook): New definition.
* utils.c (error): Use error_hook if initialized.
* sparcl-tdep.c (HAVE_SOCKETS): Don't define if GO32 or WIN32. Use
HAVE_SOCKETS in place of #ifndef GO32.
/* Caching code. Typically used by remote back ends for
caching remote memory.
- Copyright 1992, 1993 Free Software Foundation, Inc.
+ Copyright 1992, 1993, 1995 Free Software Foundation, Inc.
-This file is part of GDB.
+ 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 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.
+ 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. */
+ 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 "dcache.h"
#include "gdbcmd.h"
+#include <string.h>
-int remote_dcache = 0;
-/* In case the system header files define a prototype for insque and
- remque that uses a pointer to a struct qelem, silence the warnings */
-#define Insque(a,b) insque((PTR)(a), (PTR)(b))
-#define Remque(a) remque((PTR)(a))
+/*
+ The data cache could lead to incorrect results because it doesn't know
+ about volatile variables, thus making it impossible to debug
+ functions which use memory mapped I/O devices.
-/* The data cache records all the data read from the remote machine
- since the last time it stopped.
+ set remotecache 0
- Each cache block holds LINE_SIZE bytes of data
+ In those cases.
+
+ In general the dcache speeds up performance, some speed improvement
+ comes from the actual caching mechanism, but the major gain is in
+ the reduction of the remote protocol overhead; instead of reading
+ or writing a large area of memory in 4 byte requests, the cache
+ bundles up the requests into 32 byte (actually LINE_SIZE) chunks.
+ Reducing the overhead to an eighth of what it was. This is very
+ obvious when displaying a large amount of data,
+
+ eg, x/200x 0
+
+ caching | no yes
+ ----------------------------
+ first time | 4 sec 2 sec improvement due to chunking
+ second time | 4 sec 0 sec improvement due to caching
+
+ The cache structure is unusual, we keep a number of cache blocks
+ (DCACHE_SIZE) and each one caches a LINE_SIZEed area of memory.
+ Within each line we remember the address of the line (always a
+ multiple of the LINE_SIZE) and a vector of bytes over the range.
+ There's another vector which contains the state of the bytes.
+
+ ENTRY_BAD means that the byte is just plain wrong, and has no
+ correspondence with anything else (as it would when the cache is
+ turned on, but nothing has been done to it.
+
+ ENTRY_DIRTY means that the byte has some data in it which should be
+ written out to the remote target one day, but contains correct
+ data. ENTRY_OK means that the data is the same in the cache as it
+ is in remote memory.
+
+
+ The ENTRY_DIRTY state is necessary because GDB likes to write large
+ lumps of memory in small bits. If the caching mechanism didn't
+ maintain the DIRTY information, then something like a two byte
+ write would mean that the entire cache line would have to be read,
+ the two bytes modified and then written out again. The alternative
+ would be to not read in the cache line in the first place, and just
+ write the two bytes directly into target memory. The trouble with
+ that is that it really nails performance, because of the remote
+ protocol overhead. This way, all those little writes are bundled
+ up into an entire cache line write in one go, without having to
+ read the cache line in the first place.
+
+
+ */
+
+
+/* This value regulates the number of cache blocks stored.
+ Smaller values reduce the time spent searching for a cache
+ line, and reduce memory requirements, but increase the risk
+ of a line not being in memory */
+
+#define DCACHE_SIZE 64
+
+/* This value regulates the size of a cache line. Smaller values
+ reduce the time taken to read a single byte, but reduce overall
+ throughput. */
+
+#define LINE_SIZE_POWER (5)
+#define LINE_SIZE (1 << LINE_SIZE_POWER)
+
+/* Each cache block holds LINE_SIZE bytes of data
starting at a multiple-of-LINE_SIZE address. */
-#define LINE_SIZE_MASK ((LINE_SIZE - 1)) /* eg 7*2+1= 111*/
-#define XFORM(x) (((x) & LINE_SIZE_MASK) >> 2)
+#define LINE_SIZE_MASK ((LINE_SIZE - 1))
+#define XFORM(x) ((x) & LINE_SIZE_MASK)
+#define MASK(x) ((x) & ~LINE_SIZE_MASK)
+
+
+#define ENTRY_BAD 0 /* data at this byte is wrong */
+#define ENTRY_DIRTY 1 /* data at this byte needs to be written back */
+#define ENTRY_OK 2 /* data at this byte is same as in memory */
+
+
+struct dcache_block
+{
+ struct dcache_block *p; /* next in list */
+ unsigned int addr; /* Address for which data is recorded. */
+ unsigned char data[LINE_SIZE]; /* bytes at given address */
+ unsigned char state[LINE_SIZE]; /* what state the data is in */
+
+ /* whether anything in state is dirty - used to speed up the
+ dirty scan. */
+ int anydirty;
+
+ int refs;
+};
+
+
+struct dcache_struct
+{
+ /* Function to actually read the target memory. */
+ memxferfunc read_memory;
+
+ /* Function to actually write the target memory */
+ memxferfunc write_memory;
+
+ /* free list */
+ struct dcache_block *free_head;
+ struct dcache_block *free_tail;
+
+ /* in use list */
+ struct dcache_block *valid_head;
+ struct dcache_block *valid_tail;
+
+ /* The cache itself. */
+ struct dcache_block *the_cache;
+
+ /* potentially, if the cache was enabled, and then turned off, and
+ then turned on again, the stuff in it could be stale, so this is
+ used to mark it */
+ int cache_has_stuff;
+} ;
+
+int remote_dcache = 1;
+
+DCACHE *last_cache; /* Used by info dcache */
+
+
/* Free all the data cache blocks, thus discarding all cached data. */
+
void
dcache_flush (dcache)
DCACHE *dcache;
{
- register struct dcache_block *db;
+ int i;
+ dcache->valid_head = 0;
+ dcache->valid_tail = 0;
+
+ dcache->free_head = 0;
+ dcache->free_tail = 0;
+
+ for (i = 0; i < DCACHE_SIZE; i++)
+ {
+ struct dcache_block *db = dcache->the_cache + i;
+
+ if (!dcache->free_head)
+ dcache->free_head = db;
+ else
+ dcache->free_tail->p = db;
+ dcache->free_tail = db;
+ db->p = 0;
+ }
- if (remote_dcache > 0)
- while ((db = dcache->dcache_valid.next) != &dcache->dcache_valid)
- {
- Remque (db);
- Insque (db, &dcache->dcache_free);
- }
+ dcache->cache_has_stuff = 0;
return;
}
-/*
- * If addr is present in the dcache, return the address of the block
- * containing it.
- */
+/* If addr is present in the dcache, return the address of the block
+ containing it. */
static
struct dcache_block *
dcache_hit (dcache, addr)
{
register struct dcache_block *db;
- if (addr & 3
- || remote_dcache == 0)
- abort ();
-
/* Search all cache blocks for one that is at this address. */
- db = dcache->dcache_valid.next;
- while (db != &dcache->dcache_valid)
+ db = dcache->valid_head;
+
+ while (db)
{
- if ((addr & ~LINE_SIZE_MASK) == db->addr)
- return db;
- db = db->next;
+ if (MASK(addr) == db->addr)
+ {
+ db->refs++;
+ return db;
+ }
+ db = db->p;
}
return NULL;
}
-/* Return the int data at address ADDR in dcache block DC. */
-static
-int
-dcache_value (db, addr)
- struct dcache_block *db;
- unsigned int addr;
+/* Make sure that anything in this line which needs to
+ be written is. */
+
+static int
+dcache_write_line (dcache, db)
+ DCACHE *dcache;
+ register struct dcache_block *db;
{
- if (addr & 3
- || remote_dcache == 0)
- abort ();
- return (db->data[XFORM (addr)]);
+ int s;
+ int e;
+ s = 0;
+ if (db->anydirty)
+ {
+ for (s = 0; s < LINE_SIZE; s++)
+ {
+ if (db->state[s] == ENTRY_DIRTY)
+ {
+ int len = 0;
+ for (e = s ; e < LINE_SIZE; e++, len++)
+ if (db->state[e] != ENTRY_DIRTY)
+ {
+ /* all bytes from s..s+len-1 need to
+ be written out */
+ int done = 0;
+ while (done < len) {
+ int t = dcache->write_memory (db->addr + s + done,
+ db->data + s + done,
+ len - done);
+ if (t == 0)
+ return 0;
+ done += t;
+ }
+ memset (db->state + s, ENTRY_OK, len);
+ s = e;
+ break;
+ }
+ }
+ }
+ db->anydirty = 0;
+ }
+ return 1;
}
+
/* Get a free cache block, put or keep it on the valid list,
and return its address. The caller should store into the block
the address and data that it describes, then remque it from the
register struct dcache_block *db;
if (remote_dcache == 0)
- abort();
+ abort ();
- if ((db = dcache->dcache_free.next) == &dcache->dcache_free)
+ /* Take something from the free list */
+ if (db = dcache->free_head)
{
- /* If we can't get one from the free list, take last valid and put
- it on the free list. */
- db = dcache->dcache_valid.last;
- Remque (db);
- Insque (db, &dcache->dcache_free);
+ dcache->free_head = db->p;
+ }
+
+ if (!db)
+ {
+ /* Nothing left on free list, so grab on from the valid list */
+ db = dcache->valid_head;
+ dcache->valid_head = db->p;
+
+ dcache_write_line (dcache, db);
}
- Remque (db);
- Insque (db, &dcache->dcache_valid);
- return (db);
+ /* append this line to end of valid list */
+ if (!dcache->valid_head)
+ dcache->valid_head = db;
+ else
+ dcache->valid_tail->p = db;
+ dcache->valid_tail = db;
+ db->p = 0;
+
+ return db;
}
-/* Using the data cache DCACHE return the contents of the word at
- address ADDR in the remote machine. */
+/* Using the data cache DCACHE return the contents of the byte at
+ address ADDR in the remote machine.
+
+ Returns 0 on error. */
+
int
-dcache_fetch (dcache, addr)
+dcache_peek_byte (dcache, addr, ptr)
DCACHE *dcache;
CORE_ADDR addr;
+ unsigned char *ptr;
{
- register struct dcache_block *db;
-
- if (remote_dcache == 0)
- {
- int i;
-
- (*dcache->read_memory) (addr, (unsigned char *) &i, 4);
- return(i);
- }
-
- db = dcache_hit (dcache, addr);
- if (db == 0)
+ register struct dcache_block *db = dcache_hit (dcache, addr);
+ int ok=1;
+ int done = 0;
+ if (db == 0
+ || db->state[XFORM (addr)] == ENTRY_BAD)
{
+ if (db)
+ {
+ dcache_write_line (dcache, db);
+ }
+ else
db = dcache_alloc (dcache);
immediate_quit++;
- (*dcache->read_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
+ db->addr = MASK (addr);
+ while (done < LINE_SIZE)
+ {
+ int try =
+ (*dcache->read_memory)
+ (db->addr + done,
+ (unsigned char *) db->data + done,
+ LINE_SIZE - done);
+ if (try == 0)
+ return 0;
+ done += try;
+ }
immediate_quit--;
- db->addr = addr & ~LINE_SIZE_MASK;
- Remque (db); /* Off the free list */
- Insque (db, &dcache->dcache_valid); /* On the valid list */
+
+ memset (db->state, ENTRY_OK, sizeof (db->data));
+ db->anydirty = 0;
}
- return (dcache_value (db, addr));
+ *ptr = db->data[XFORM (addr)];
+ return ok;
}
-/* Write the word at ADDR both in the data cache and in the remote machine. */
-void
-dcache_poke (dcache, addr, data)
+/* Using the data cache DCACHE return the contents of the word at
+ address ADDR in the remote machine.
+
+ Returns 0 on error. */
+
+int
+dcache_peek (dcache, addr, data)
DCACHE *dcache;
CORE_ADDR addr;
- int data;
+ int *data;
{
- register struct dcache_block *db;
+ unsigned char *dp = (unsigned char *) data;
+ int i;
+ for (i = 0; i < sizeof (int); i++)
+ {
+ if (!dcache_peek_byte (dcache, addr, dp + i))
+ return 0;
+ }
+ return 1;
+}
- if (remote_dcache == 0)
+
+/* Writeback any dirty lines to the remote. */
+static int
+dcache_writeback (dcache)
+ DCACHE *dcache;
+{
+ struct dcache_block *db;
+
+ db = dcache->valid_head;
+
+ while (db)
{
- (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
- return;
+ if (!dcache_write_line (dcache, db))
+ return 0;
+ db = db->p;
}
+ return 1;
+}
- /* First make sure the word is IN the cache. DB is its cache block. */
- db = dcache_hit (dcache, addr);
- if (db == 0)
+
+/* Using the data cache DCACHE return the contents of the word at
+ address ADDR in the remote machine. */
+int
+dcache_fetch (dcache, addr)
+ DCACHE *dcache;
+ CORE_ADDR addr;
+{
+ int res;
+ dcache_peek (dcache, addr, &res);
+ return res;
+}
+
+
+/* Write the byte at PTR into ADDR in the data cache.
+ Return zero on write error.
+ */
+
+int
+dcache_poke_byte (dcache, addr, ptr)
+ DCACHE *dcache;
+ CORE_ADDR addr;
+ char *ptr;
+{
+ register struct dcache_block *db = dcache_hit (dcache, addr);
+
+ if (!db)
{
db = dcache_alloc (dcache);
- immediate_quit++;
- (*dcache->write_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
- immediate_quit--;
- db->addr = addr & ~LINE_SIZE_MASK;
- Remque (db); /* Off the free list */
- Insque (db, &dcache->dcache_valid); /* On the valid list */
+ db->addr = MASK (addr);
+ memset (db->state, ENTRY_BAD, sizeof (db->data));
}
- /* Modify the word in the cache. */
- db->data[XFORM (addr)] = data;
+ db->data[XFORM (addr)] = *ptr;
+ db->state[XFORM (addr)] = ENTRY_DIRTY;
+ db->anydirty = 1;
+ return 1;
+}
- /* Send the changed word. */
- immediate_quit++;
- (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
- immediate_quit--;
+/* Write the word at ADDR both in the data cache and in the remote machine.
+ Return zero on write error.
+ */
+
+int
+dcache_poke (dcache, addr, data)
+ DCACHE *dcache;
+ CORE_ADDR addr;
+ int data;
+{
+ unsigned char *dp = (unsigned char *) (&data);
+ int i;
+ for (i = 0; i < sizeof (int); i++)
+ {
+ if (!dcache_poke_byte (dcache, addr, dp + i))
+ return 0;
+ }
+ dcache_writeback (dcache);
+ return 1;
}
+
/* Initialize the data cache. */
DCACHE *
dcache_init (reading, writing)
memxferfunc reading;
memxferfunc writing;
{
- register i;
- register struct dcache_block *db;
+ int csize = sizeof (struct dcache_block) * DCACHE_SIZE;
DCACHE *dcache;
dcache = (DCACHE *) xmalloc (sizeof (*dcache));
dcache->read_memory = reading;
dcache->write_memory = writing;
- dcache->the_cache = (struct dcache_block *)
- xmalloc (sizeof (*dcache->the_cache) * DCACHE_SIZE);
- dcache->dcache_free.next = dcache->dcache_free.last = &dcache->dcache_free;
- dcache->dcache_valid.next = dcache->dcache_valid.last = &dcache->dcache_valid;
- for (db = dcache->the_cache, i = 0; i < DCACHE_SIZE; i++, db++)
- Insque (db, &dcache->dcache_free);
+ dcache->the_cache = (struct dcache_block *) xmalloc (csize);
+ memset (dcache->the_cache, 0, csize);
+
+ dcache_flush (dcache);
+
+ last_cache = dcache;
+ return dcache;
+}
+
+/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
+ to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is
+ nonzero.
+
+ Returns length of data written or read; 0 for error.
+
+ This routine is indended to be called by remote_xfer_ functions. */
+
+int
+dcache_xfer_memory (dcache, memaddr, myaddr, len, should_write)
+ DCACHE *dcache;
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int should_write;
+{
+ int i;
+
+ if (remote_dcache)
+ {
+ int (*xfunc) ()
+ = should_write ? dcache_poke_byte : dcache_peek_byte;
+
+ for (i = 0; i < len; i++)
+ {
+ if (!xfunc (dcache, memaddr + i, myaddr + i))
+ return 0;
+ }
+ dcache->cache_has_stuff = 1;
+ dcache_writeback (dcache);
+ }
+ else
+ {
+ int (*xfunc) ()
+ = should_write ? dcache->write_memory : dcache->read_memory;
+
+ if (dcache->cache_has_stuff)
+ dcache_flush (dcache);
- return(dcache);
+ len = xfunc (memaddr, myaddr, len);
+ }
+ return len;
+}
+
+static void
+dcache_info (exp, tty)
+ char *exp;
+ int tty;
+{
+ struct dcache_block *p;
+
+ if (!remote_dcache)
+ {
+ printf_filtered ("Dcache not enabled\n");
+ return;
+ }
+ printf_filtered ("Dcache enabled, line width %d, depth %d\n",
+ LINE_SIZE, DCACHE_SIZE);
+
+ printf_filtered ("Cache state:\n");
+
+ for (p = last_cache->valid_head; p; p = p->p)
+ {
+ int j;
+ printf_filtered ("Line at %08xd, referenced %d times\n",
+ p->addr, p->refs);
+
+ for (j = 0; j < LINE_SIZE; j++)
+ printf_filtered ("%02x", p->data[j]);
+ printf_filtered ("\n");
+
+ for (j = 0; j < LINE_SIZE; j++)
+ printf_filtered ("% 2x", p->state[j]);
+ printf_filtered ("\n");
+ }
}
void
-_initialitize_dcache ()
+_initialize_dcache ()
{
add_show_from_set
(add_set_cmd ("remotecache", class_support, var_boolean,
this option can offer better throughput for reading target memory.\n\
Unfortunately, gdb does not currently know anything about volatile\n\
registers and thus data caching will produce incorrect results with\n\
-volatile registers are in use. By default, this option is off.",
+volatile registers are in use. By default, this option is on.",
&setlist),
&showlist);
+
+ add_info ("dcache", dcache_info,
+ "Print information on the dcache performance.");
+
}
#ifndef DCACHE_H
#define DCACHE_H
-/* The data cache leads to incorrect results because it doesn't know about
- volatile variables, thus making it impossible to debug functions which
- use hardware registers. Therefore it is #if 0'd out. Effect on
- performance is some, for backtraces of functions with a few
- arguments each. For functions with many arguments, the stack
- frames don't fit in the cache blocks, which makes the cache less
- helpful. Disabling the cache is a big performance win for fetching
- large structures, because the cache code fetched data in 16-byte
- chunks. */
-
-#define LINE_SIZE_POWER (4)
-/* eg 1<<3 == 8 */
-#define LINE_SIZE (1 << LINE_SIZE_POWER)
-/* Number of cache blocks */
-#define DCACHE_SIZE (64)
-
-struct dcache_block
-{
- struct dcache_block *next, *last;
- unsigned int addr; /* Address for which data is recorded. */
- int data[LINE_SIZE / sizeof (int)];
-};
-
typedef int (*memxferfunc) PARAMS((CORE_ADDR memaddr,
unsigned char *myaddr,
int len));
-typedef struct {
- /* Function to actually read the target memory. */
- memxferfunc read_memory;
-
- /* Function to actually write the target memory */
- memxferfunc write_memory;
-
- /* free list */
- struct dcache_block dcache_free;
-
- /* in use list */
- struct dcache_block dcache_valid;
-
- /* The cache itself. */
- struct dcache_block *the_cache;
-
-} DCACHE;
+typedef struct dcache_struct DCACHE;
/* Using the data cache DCACHE return the contents of the word at
address ADDR in the remote machine. */
DCACHE *dcache_init PARAMS((memxferfunc reading, memxferfunc writing));
/* Write the word at ADDR both in the data cache and in the remote machine. */
-void dcache_poke PARAMS((DCACHE *dcache, CORE_ADDR addr, int data));
+int dcache_poke PARAMS((DCACHE *dcache, CORE_ADDR addr, int data));
+
+/* Simple to call from <remote>_xfer_memory */
+
+int dcache_xfer_memory PARAMS((DCACHE *cache, CORE_ADDR mem, char *my, int len, int should_write));
+/* Write the bytes at ADDR into the data cache and the remote machine. */
+int dcache_poke_block PARAMS((DCACHE *cache, CORE_ADDR mem, char* my, int len));
#endif /* DCACHE_H */
#include "ansidecl.h"
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
#include "libiberty.h"
/* libiberty.h can't declare this one, but evidently we can. */
extern void puts_unfiltered PARAMS ((char *));
-extern void vprintf_filtered PARAMS ((char *, ...))
+extern void vprintf_filtered PARAMS ((char *, va_list))
ATTR_FORMAT(printf, 1, 0);
-extern void vfprintf_filtered PARAMS ((FILE *, char *, ...))
+extern void vfprintf_filtered PARAMS ((FILE *, char *, va_list))
ATTR_FORMAT(printf, 2, 0);
extern void fprintf_filtered PARAMS ((FILE *, char *, ...))
extern void printfi_filtered PARAMS ((int, char *, ...))
ATTR_FORMAT(printf, 2, 3);
-extern void vprintf_unfiltered PARAMS ((char *, ...))
+extern void vprintf_unfiltered PARAMS ((char *, va_list))
ATTR_FORMAT(printf, 1, 0);
-extern void vfprintf_unfiltered PARAMS ((FILE *, char *, ...))
+extern void vfprintf_unfiltered PARAMS ((FILE *, char *, va_list))
ATTR_FORMAT(printf, 2, 0);
extern void fprintf_unfiltered PARAMS ((FILE *, char *, ...))
#endif /* MALLOC_INCOMPATIBLE */
+#ifndef WIN32
extern char *strchr ();
extern char *strrchr ();
extern char *strtok ();
extern char *strerror ();
+#endif
/* Various possibilities for alloca. */
#ifndef alloca
#define MAINTENANCE_CMDS 1
#endif
+#ifdef MAINTENANCE_CMDS
+extern int watchdog;
+#endif
+
#include "dis-asm.h" /* Get defs for disassemble_info */
extern int dis_asm_read_memory PARAMS ((bfd_vma memaddr, bfd_byte *myaddr,
extern void (*call_command_hook) PARAMS ((struct cmd_list_element *c,
char *cmd, int from_tty));
+extern NORETURN void (*error_hook) PARAMS (());
+
+
+
/* Inhibit window interface if non-zero. */
extern int use_windows;
+/* Symbolic definitions of filename-related things. */
+/* FIXME, this doesn't work very well if host and executable
+ filesystems conventions are different. */
+
+#ifndef DIRNAME_SEPARATOR
+#define DIRNAME_SEPARATOR ':'
+#endif
+
+#ifndef SLASH_P
+#define SLASH_P(X) ((X)=='/')
+#endif
+
+#ifndef SLASH_CHAR
+#define SLASH_CHAR '/'
+#endif
+
+#ifndef SLASH_STRING
+#define SLASH_STRING "/"
+#endif
+
+#ifndef ROOTED_P
+#define ROOTED_P(X) (SLASH_P((X)[0]))
+#endif
+
#endif /* #ifndef DEFS_H */
#include "gdbcmd.h"
#include "inferior.h"
#include "regex.h"
+#include "dcache.h"
static int readchar PARAMS ((int timeout));
static void monitor_mourn_inferior PARAMS ((void));
static void monitor_stop PARAMS ((void));
+static int monitor_read_memory PARAMS ((CORE_ADDR addr, char *myaddr,int len));
+static int monitor_write_memory PARAMS ((CORE_ADDR addr, char *myaddr,int len));
+
static int from_hex PARAMS ((int a));
static unsigned long get_hex_word PARAMS ((void));
static int dump_reg_flag; /* Non-zero means do a dump_registers cmd when
monitor_wait wakes up. */
+static DCACHE *remote_dcache;
+
/* monitor_printf_noecho -- Send data to monitor, but don't expect an echo.
Works just like printf. */
if (c != sndbuf[i])
{
+ /* Don't fail if we sent a ^C, they're never echoed */
+ if (sndbuf[i] == '\003')
+ continue;
#if 0
if (sndbuf[i] == '\r'
&& c == '\n')
goto trycr;
#endif
- error ("monitor_printf: Bad echo. Sent: \"%s\", Got: \"%.*s%c\".",
+ warning ("monitor_printf: Bad echo. Sent: \"%s\", Got: \"%.*s%c\".",
sndbuf, i, sndbuf, c);
}
}
monitor_printf (current_monitor->line_term);
+ remote_dcache = dcache_init (monitor_read_memory, monitor_write_memory);
+
start_remote ();
}
int pid, step;
enum target_signal sig;
{
+ dcache_flush (remote_dcache);
if (step)
monitor_printf (STEP_CMD);
else
continue;
error ("monitor_fetch_register (%d): bad response from monitor: %.*s%c.",
- regno, i, regbuf, c);
+ regno, i, regbuf, c);
}
regbuf[i] = c;
/* Read the remote registers into the block regs. */
+static void monitor_dump_regs ()
+{
+ if (current_monitor->dump_registers)
+ {
+ char buf[200];
+ int resp_len;
+ monitor_printf (current_monitor->dump_registers);
+ resp_len = monitor_expect_prompt (buf, sizeof (buf));
+ parse_register_dump (buf, resp_len);
+ }
+ else
+ abort(); /* Need some way to read registers */
+}
+
static void
monitor_fetch_registers (regno)
int regno;
{
- if (regno >= 0)
+ if (current_monitor->getreg.cmd)
{
- monitor_fetch_register (regno);
- return;
- }
+ if (regno >= 0)
+ {
+ monitor_fetch_register (regno);
+ return;
+ }
- for (regno = 0; regno < NUM_REGS; regno++)
- monitor_fetch_register (regno);
+ for (regno = 0; regno < NUM_REGS; regno++)
+ monitor_fetch_register (regno);
+ }
+ else {
+ monitor_dump_regs ();
+ }
}
/* Store register REGNO, or all if REGNO == 0. Return errno value. */
int write;
struct target_ops *target; /* ignored */
{
- if (write)
- return monitor_write_memory (memaddr, myaddr, len);
- else
- return monitor_read_memory (memaddr, myaddr, len);
+ return dcache_xfer_memory (remote_dcache, memaddr, myaddr, len, write);
}
static void
char *file;
int from_tty;
{
+ dcache_flush (remote_dcache);
+
if (current_monitor->load_routine)
current_monitor->load_routine (monitor_desc, file, hashmark);
else
/* Finally, make the PC point at the start address */
- write_pc (bfd_get_start_address (exec_bfd));
+ if (exec_bfd)
+ write_pc (bfd_get_start_address (exec_bfd));
inferior_pid = 0; /* No process now */
return;
}
- monitor_printf (LOAD_CMD); /* tell the monitor to load */
+ monitor_printf (LOAD_CMD); /* tell the monitor to load */
if (current_monitor->loadresp)
monitor_expect (current_monitor->loadresp, NULL, 0);
for (s = abfd->sections; s; s = s->next)
- if (s->flags & SEC_LOAD)
- {
- printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma,
- s->vma + s->_raw_size);
- gdb_flush (gdb_stdout);
+ {
+ if (s->flags & SEC_LOAD)
+ {
+ int numbytes;
- for (i = 0; i < s->_raw_size; i += srec_frame)
- {
- int numbytes;
+ printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma,
+ s->vma + s->_raw_size);
+ gdb_flush (gdb_stdout);
- numbytes = min (srec_frame, s->_raw_size - i);
+ for (i = 0; i < s->_raw_size; i += numbytes)
+ {
+ numbytes = min (srec_frame, s->_raw_size - i);
- bfd_get_section_contents (abfd, s, buffer, i, numbytes);
+ bfd_get_section_contents (abfd, s, buffer, i, numbytes);
- reclen = monitor_make_srec (srec, 3, s->vma + i, buffer, numbytes);
+ reclen = monitor_make_srec (srec, 'd', s->vma + i, buffer, numbytes);
- monitor_printf_noecho ("%.*s\r", reclen, srec);
+ monitor_printf_noecho ("%.*s\r", reclen, srec);
- if (hashmark)
- {
- putchar_unfiltered ('#');
- gdb_flush (gdb_stdout);
- }
- } /* Per-packet (or S-record) loop */
+ if (hashmark)
+ {
+ putchar_unfiltered ('#');
+ gdb_flush (gdb_stdout);
+ }
+ } /* Per-packet (or S-record) loop */
- putchar_unfiltered ('\n');
- } /* Loadable sections */
-
+ putchar_unfiltered ('\n');
+ } /* Loadable sections */
+ }
if (hashmark)
putchar_unfiltered ('\n');
/* Write a type 7 terminator record. no data for a type 7, and there
is no data, so len is 0. */
- reclen = monitor_make_srec (srec, 7, abfd->start_address, NULL, 0);
+ reclen = monitor_make_srec (srec, 't', abfd->start_address, NULL, 0);
monitor_printf_noecho ("%.*s\r", reclen, srec);
unsigned char checksum;
int i;
char *buf;
- static char hextab[] = "0123456789ABCDEF";
-
+ static char hextab[16] = "0123456789ABCDEF";
+ static char data_code_table[] = { 0,0,1,2,3};
+ static char term_code_table[] = { 0,0,9,8,7};
+ int addr_size; /* Number of bytes in the record */
+ int type_code;
buf = buffer;
checksum = 0;
- /* Create the header for the srec. 4 is the number of bytes in the address,
+ addr_size = 2;
+ if (memaddr >= 0xffffff)
+ addr_size = 4;
+ else if (memaddr >= 0xffffff)
+ addr_size = 3;
+ else
+ addr_size = 2;
+
+ switch (type)
+ {
+ case 't':
+ type_code = term_code_table[addr_size];
+ break;
+ case 'd':
+ type_code = data_code_table[addr_size];
+ break;
+ default:
+ abort();
+ }
+ /* Create the header for the srec. addr_size is the number of bytes in the address,
and 1 is the number of bytes in the count. */
- sprintf (buf, "S%d%02X%08X", type, len + 4 + 1, memaddr);
- buf += 12;
-
+ switch (addr_size)
+ {
+ case 4:
+ sprintf (buf, "S%d%02X%08X", type_code, len + addr_size + 1, memaddr);
+ buf += 12;
+ break;
+ case 3:
+ sprintf (buf, "S%d%02X%06X", type_code, len + addr_size + 1, memaddr);
+ buf += 10;
+ break;
+ case 2:
+ sprintf (buf, "S%d%02X%04X", type_code, len + addr_size + 1, memaddr);
+ buf += 8;
+ break;
+ }
+
/* Note that the checksum is calculated on the raw data, not the hexified
data. It includes the length, address and the data portions of the
packet. */
- checksum += (len + 4 + 1 /* Packet length */
+ checksum += (len + addr_size + 1 /* Packet length */
+ (memaddr & 0xff) /* Address... */
+ ((memaddr >> 8) & 0xff)
+ ((memaddr >> 16) & 0xff)
"tl\r", /* download command */
NULL, /* load response */
">", /* monitor command prompt */
- NULL, /* end-of-command delimitor */
+ "\r", /* end-of-command delimitor */
NULL, /* optional command terminator */
&hms_ops, /* target operations */
SERIAL_1_STOPBITS, /* number of stop bits */
static int quiet = 1; /* FIXME - can be removed after Dec '94 */
-DCACHE *dcache_ptr;
-int remote_dcache;
-serial_t desc;
/***********************************************************************
SERIAL_CLOSE (desc);
}
is_open = 0;
- remote_dcache = 0;
}
/* Terminate the open connection to the remote debugger. Use this
enum target_signal
sig;
{
- dcache_flush (dcache_ptr);
-
if (step)
{
hms_write_cr ("s");
}
-/* Read a word from remote address ADDR and return it.
- * This goes through the data cache.
- */
-int
-hms_fetch_word (addr)
- CORE_ADDR addr;
-{
- return dcache_fetch (dcache_ptr, addr);
-}
-
-/* Write a word WORD into remote address ADDR.
- This goes through the data cache. */
-
-void
-hms_store_word (addr, word)
- CORE_ADDR addr;
- int word;
-{
- dcache_poke (dcache_ptr, addr, word);
-}
int
hms_xfer_inferior_memory (memaddr, myaddr, len, write, target)
int write;
struct target_ops *target; /* ignored */
{
- register int i;
-
- /* Round starting address down to longword boundary. */
- register CORE_ADDR addr;
-
- /* Round ending address up; get number of longwords that makes. */
- register int count;
-
- /* Allocate buffer of that many longwords. */
- register int *buffer;
-
- memaddr &= 0xffff;
- addr = memaddr & -sizeof (int);
- count = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
-
- buffer = (int *) alloca (count * sizeof (int));
-
- if (write)
- {
- /* Fill start and end extra bytes of buffer with existing memory data. */
-
- if (addr != memaddr || len < (int) sizeof (int))
- {
- /* Need part of initial word -- fetch it. */
- buffer[0] = hms_fetch_word (addr);
- }
-
- if (count > 1) /* FIXME, avoid if even boundary */
- {
- buffer[count - 1]
- = hms_fetch_word (addr + (count - 1) * sizeof (int));
- }
-
- /* Copy data to be written over corresponding part of buffer */
-
- memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
-
- /* Write the entire buffer. */
-
- for (i = 0; i < count; i++, addr += sizeof (int))
- {
- errno = 0;
- hms_store_word (addr, buffer[i]);
- if (errno)
- {
- return 0;
- }
-
- }
- }
- else
- {
- /* Read all the longwords */
- for (i = 0; i < count; i++, addr += sizeof (int))
- {
- errno = 0;
- buffer[i] = hms_fetch_word (addr);
- if (errno)
- {
- return 0;
- }
- QUIT;
- }
-
- /* Copy appropriate bytes out of the buffer. */
- memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
- }
return len;
}
/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright 1988, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1988, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcmd.h"
#include "objfiles.h"
#include "gdb-stabs.h"
+#include "thread.h"
#include "dcache.h"
/* Prototypes for local functions */
-static int
-remote_write_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+static int remote_write_bytes PARAMS ((CORE_ADDR memaddr,
+ unsigned char *myaddr, int len));
-static int
-remote_read_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+static int remote_read_bytes PARAMS ((CORE_ADDR memaddr,
+ unsigned char *myaddr, int len));
-static void
-remote_files_info PARAMS ((struct target_ops *ignore));
+static void remote_files_info PARAMS ((struct target_ops *ignore));
-static int
-remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
- int should_write, struct target_ops *target));
+static int remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr,
+ int len, int should_write,
+ struct target_ops *target));
-static void
-remote_prepare_to_store PARAMS ((void));
+static void remote_prepare_to_store PARAMS ((void));
-static void
-remote_fetch_registers PARAMS ((int regno));
+static void remote_fetch_registers PARAMS ((int regno));
-static void
-remote_resume PARAMS ((int pid, int step, enum target_signal siggnal));
+static void remote_resume PARAMS ((int pid, int step,
+ enum target_signal siggnal));
-static int
-remote_start_remote PARAMS ((char *dummy));
+static int remote_start_remote PARAMS ((char *dummy));
-static void
-remote_open PARAMS ((char *name, int from_tty));
+static void remote_open PARAMS ((char *name, int from_tty));
-static void
-remote_close PARAMS ((int quitting));
+static void remote_close PARAMS ((int quitting));
-static void
-remote_store_registers PARAMS ((int regno));
+static void remote_store_registers PARAMS ((int regno));
-static void
-getpkt PARAMS ((char *buf, int forever));
+static void getpkt PARAMS ((char *buf, int forever));
-static int
-putpkt PARAMS ((char *buf));
+static int putpkt PARAMS ((char *buf));
-static void
-remote_send PARAMS ((char *buf));
+static void remote_send PARAMS ((char *buf));
-static int
-readchar PARAMS ((int timeout));
+static int readchar PARAMS ((int timeout));
static int remote_wait PARAMS ((int pid, struct target_waitstatus *status));
-static int
-tohex PARAMS ((int nib));
+static void remote_kill PARAMS ((void));
-static int
-fromhex PARAMS ((int a));
+static int tohex PARAMS ((int nib));
-static void
-remote_detach PARAMS ((char *args, int from_tty));
+static int fromhex PARAMS ((int a));
-static void
-remote_interrupt PARAMS ((int signo));
+static void remote_detach PARAMS ((char *args, int from_tty));
-static void
-remote_interrupt_twice PARAMS ((int signo));
+static void remote_interrupt PARAMS ((int signo));
-static void
-interrupt_query PARAMS ((void));
+static void remote_interrupt_twice PARAMS ((int signo));
+
+static void interrupt_query PARAMS ((void));
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 remote_timeout = 2;
-#if 0
-int icache;
-#endif
+static int remote_timeout = 2;
/* Descriptor for I/O to remote machine. Initialize it to NULL so that
remote_open knows that we don't have a file open when the program
+ symfile_objfile->num_sections
* sizeof (offs->offsets));
- /* FIXME: This code assumes gdb-stabs.h is being used; it's broken
- for xcoff, dwarf, sdb-coff, etc. But there is no simple
- canonical representation for this stuff. (Just what does "text"
- as seen by the stub mean, anyway? I think it means all sections
- with SEC_CODE set, but we currently have no way to deal with that). */
-
ANOFFSET (offs, SECT_OFF_TEXT) = text_addr;
/* This is a temporary kludge to force data and bss to use the same offsets
immediate_quit = 1; /* Allow user to interrupt it */
/* Ack any packet which the remote side has already sent. */
-
SERIAL_WRITE (remote_desc, "+", 1);
/* Let the stub know that we want it to return the thread. */
immediate_quit = 0;
start_remote (); /* Initialize gdb process mechanisms */
-
return 1;
}
int from_tty;
{
if (name == 0)
- error (
-"To open a remote debug connection, you need to specify what serial\n\
+ error ("To open a remote debug connection, you need to specify what serial\n\
device is attached to the remote system (e.g. /dev/ttya).");
target_preopen (from_tty);
}
}
+
SERIAL_RAW (remote_desc);
/* If there is something sitting in the buffer we might take it as a
several processes. */
inferior_pid = 42000;
-
/* Start the remote connection; if error (0), discard this target.
In particular, if the user quits, be sure to discard it
(we'd be in an inconsistent state otherwise). */
if (!catch_errors (remote_start_remote, (char *)0,
- "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
+ "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
pop_target();
}
while (*p)
{
unsigned char *p1;
+ char *p_temp;
- regno = strtol (p, &p1, 16); /* Read the register number */
+ regno = strtol (p, &p_temp, 16); /* Read the register number */
+ p1 = (unsigned char *)p_temp;
if (p1 == p)
{
p, buf);
if (strncmp (p, "thread", p1 - p) == 0)
{
- char *p2;
- thread_num = strtol (++p1, &p, 16);
+ thread_num = strtol (++p1, &p_temp, 16);
+ p = (unsigned char *)p_temp;
}
}
else
remote_send (buf);
}
-#if 0
-
-/* Use of the data cache is disabled because it loses for looking at
+/*
+ Use of the data cache *used* to be disabled because it loses for looking at
and changing hardware I/O ports and the like. Accepting `volatile'
- would perhaps be one way to fix it, but a better way which would
- win for more cases would be to use the executable file for the text
- segment, like the `icache' code below but done cleanly (in some
- target-independent place, perhaps in target_xfer_memory, perhaps
- based on assigning each target a speed or perhaps by some simpler
- mechanism). */
+ would perhaps be one way to fix it. Another idea would be to use the
+ executable file for the text segment (for all SEC_CODE sections?
+ For all SEC_READONLY sections?). This has problems if you want to
+ actually see what the memory contains (e.g. self-modifying code,
+ clobbered memory, user downloaded the wrong thing).
+
+ Because it speeds so much up, it's now enabled, if you're playing
+ with registers you turn it of (set remotecache 0)
+*/
/* Read a word from remote address ADDR and return it.
This goes through the data cache. */
remote_fetch_word (addr)
CORE_ADDR addr;
{
-#if 0
- if (icache)
- {
- extern CORE_ADDR text_start, text_end;
-
- if (addr >= text_start && addr < text_end)
- {
- int buffer;
- target_read_memory (addr, &buffer, sizeof (int));
- return buffer;
- }
- }
-#endif
return dcache_fetch (remote_dcache, addr);
}
{
dcache_poke (remote_dcache, addr, word);
}
-#endif /* 0 */
+
\f
/* Write memory data directly to the remote machine.
This does not inform the data cache; the data cache uses this.
int should_write;
struct target_ops *target; /* ignored */
{
- int xfersize;
- int bytes_xferred;
- int total_xferred = 0;
-
- set_thread (inferior_pid, 1);
-
- while (len > 0)
- {
- if (len > MAXBUFBYTES)
- xfersize = MAXBUFBYTES;
- else
- xfersize = len;
-
- if (should_write)
- bytes_xferred = remote_write_bytes (memaddr,
- (unsigned char *)myaddr, xfersize);
- else
- bytes_xferred = remote_read_bytes (memaddr,
- (unsigned char *)myaddr, xfersize);
-
- /* If we get an error, we are done xferring. */
- if (bytes_xferred == 0)
- break;
-
- memaddr += bytes_xferred;
- myaddr += bytes_xferred;
- len -= bytes_xferred;
- total_xferred += bytes_xferred;
- }
- return total_xferred;
+ return dcache_xfer_memory (remote_dcache, memaddr, myaddr, len, should_write);
}
+
#if 0
/* Enable after 4.12. */
remote_send (buf)
char *buf;
{
-
putpkt (buf);
getpkt (buf, 0);
char buf2[PBUFSIZ];
int cnt = strlen (buf);
int ch;
+ int tcount = 0;
char *p;
/* Copy the packet into buffer BUF2, encapsulating it
{
ch = readchar (remote_timeout);
- if (remote_debug)
+ if (remote_debug)
{
switch (ch)
{
case '$':
if (started_error_output)
{
- putc_unfiltered ('\n');
+ putchar_unfiltered ('\n');
started_error_output = 0;
}
}
printf_unfiltered("Ack\n");
return 1;
case SERIAL_TIMEOUT:
+ tcount ++;
+ if (tcount > 3)
+ return 0;
break; /* Retransmit buffer */
case '$':
{
started_error_output = 1;
printf_unfiltered ("putpkt: Junk: ");
}
- putc_unfiltered (ch & 0177);
+ putchar_unfiltered (ch & 0177);
}
continue;
}
int timeout;
int val;
+ strcpy (buf,"timeout");
+
if (forever)
- timeout = -1;
+ {
+#ifdef MAINTENANCE_CMDS
+ timeout = watchdog > 0 ? watchdog : -1;
+#else
+ timeout = -1;
+#endif
+ }
+
else
timeout = remote_timeout;
-#define MAX_TRIES 10
+#define MAX_TRIES 3
for (tries = 1; tries <= MAX_TRIES; tries++)
{
if (c == SERIAL_TIMEOUT)
{
+#ifdef MAINTENANCE_CMDS
+ if (forever) /* Watchdog went off. Kill the target. */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+#endif
if (remote_debug)
puts_filtered ("Timed out.\n");
goto retry;
}
/* Try the whole thing again. */
-retry:
+ retry:
SERIAL_WRITE (remote_desc, "-", 1);
}
#include "serial.h"
#include <sys/types.h>
#include <sys/time.h>
-#ifndef __GO32__
+
+#if defined(__GO32__) || defined(WIN32)
+#undef HAVE_SOCKETS
+#else
+#define HAVE_SOCKETS
+#endif
+
+
+#ifdef HAVE_SOCKETS
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
static char *remote_target_name = NULL;
static serial_t remote_desc = NULL;
static int serial_flag;
-#ifndef __GO32__
+#ifdef HAVE_SOCKETS
static int udp_fd = -1;
#endif
static serial_t open_tty PARAMS ((char *name));
static int send_resp PARAMS ((serial_t desc, char c));
static void close_tty PARAMS ((int ignore));
-#ifndef __GO32__
+#ifdef HAVE_SOCKETS
static int recv_udp_buf PARAMS ((int fd, unsigned char *buf, int len, int timeout));
static int send_udp_buf PARAMS ((int fd, unsigned char *buf, int len));
#endif
static void sparclite_serial_write PARAMS ((bfd *from_bfd, asection *from_sec,
file_ptr from_addr,
bfd_vma to_addr, int len));
-#ifndef __GO32__
+#ifdef HAVE_SOCKETS
static unsigned short calc_checksum PARAMS ((unsigned char *buffer,
int count));
static void sparclite_udp_start PARAMS ((bfd_vma entry));
remote_desc = NULL;
}
-#ifndef __GO32__
+#ifdef HAVE_SOCKETS
static int
recv_udp_buf (fd, buf, len, timeout)
int fd, len;
}
else
{
-#ifndef __GO32__
+#ifdef HAVE_SOCKETS
struct hostent *he;
struct sockaddr_in sockaddr;
unsigned char buffer[100];
{
if (serial_flag)
close_tty (0);
-#ifndef __GO32__
+#ifdef HAVE_SOCKETS
else
if (udp_fd != -1)
close (udp_fd);
error ("Bad checksum from load command (0x%x)", i);
}
-#ifndef __GO32__
+#ifdef HAVE_SOCKETS
static unsigned short
calc_checksum (buffer, count)
int from_tty;
{
if (!serial_flag)
-#ifndef __GO32__
+#ifdef HAVE_SOCKETS
download (remote_target_name, filename, from_tty, sparclite_udp_write,
sparclite_udp_start);
#else
void (*call_command_hook) PARAMS ((struct cmd_list_element *c, char *cmd,
int from_tty));
+
+
+/* Takes control from error (). Typically used to prevent longjmps out of the
+ middle of the GUI. Usually used in conjunction with a catch routine. */
+
+NORETURN void (*error_hook) PARAMS (());
+
\f
/* Where to go for return_to_top_level (RETURN_ERROR). */
jmp_buf error_return;
#include <sys/param.h>
#include <pwd.h>
#endif
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
#include <stdarg.h>
#else
#include <varargs.h>
/* VARARGS */
void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
warning (char *string, ...)
#else
warning (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, string);
#else
char *string;
The first argument STRING is the error message, used as a fprintf string,
and the remaining args are passed as arguments to it. */
-/* VARARGS */
+#ifdef ANSI_PROTOTYPES
NORETURN void
-#ifdef __STDC__
error (char *string, ...)
#else
error (va_alist)
va_dcl
#endif
{
+#ifdef ANSI_PROTOTYPES
va_list args;
-#ifdef __STDC__
va_start (args, string);
#else
- char *string;
-
va_start (args);
- string = va_arg (args, char *);
#endif
- error_begin ();
- vfprintf_filtered (gdb_stderr, string, args);
- fprintf_filtered (gdb_stderr, "\n");
- va_end (args);
- return_to_top_level (RETURN_ERROR);
+ if (error_hook)
+ error_hook();
+ else
+ {
+ char *string1;
+ error_begin ();
+#ifdef ANSI_PROTOTYPES
+ vfprintf_filtered (gdb_stderr, string, args);
+#else
+ string1 = va_arg (args, char *);
+ vfprintf_filtered (gdb_stderr, string1, args);
+#endif
+ fprintf_filtered (gdb_stderr, "\n");
+ va_end (args);
+ return_to_top_level (RETURN_ERROR);
+ }
}
+
/* Print an error message and exit reporting failure.
This is for a error that we cannot continue from.
The arguments are printed a la printf.
/* VARARGS */
NORETURN void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
fatal (char *string, ...)
#else
fatal (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, string);
#else
char *string;
-
va_start (args);
string = va_arg (args, char *);
#endif
/* VARARGS */
static void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
fatal_dump_core (char *string, ...)
#else
fatal_dump_core (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, string);
#else
char *string;
/* VARARGS */
int
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
query (char *ctlstr, ...)
#else
query (va_alist)
register int ans2;
int retval;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, ctlstr);
#else
char *ctlstr;
/* VARARGS */
void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
fprintf_filtered (FILE *stream, char *format, ...)
#else
fprintf_filtered (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, format);
#else
FILE *stream;
/* VARARGS */
void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
fprintf_unfiltered (FILE *stream, char *format, ...)
#else
fprintf_unfiltered (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, format);
#else
FILE *stream;
/* VARARGS */
void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
fprintfi_filtered (int spaces, FILE *stream, char *format, ...)
#else
fprintfi_filtered (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, format);
#else
int spaces;
/* VARARGS */
void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
printf_filtered (char *format, ...)
#else
printf_filtered (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, format);
#else
char *format;
/* VARARGS */
void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
printf_unfiltered (char *format, ...)
#else
printf_unfiltered (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, format);
#else
char *format;
/* VARARGS */
void
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
printfi_filtered (int spaces, char *format, ...)
#else
printfi_filtered (va_alist)
#endif
{
va_list args;
-#ifdef __STDC__
+#ifdef ANSI_PROTOTYPES
va_start (args, format);
#else
int spaces;