/* Remote debugging interface for MIPS remote debugging protocol.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2003, 2004, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Cygnus Support. Written by Ian Lance Taylor
<ian@cygnus.com>.
#include "regcache.h"
#include <ctype.h>
#include "mips-tdep.h"
+#include "gdbthread.h"
\f
/* Breakpoint types. Values 0, 1, and 2 must agree with the watch
static void mips_close (int quitting);
-static void mips_detach (char *args, int from_tty);
-
-static void mips_resume (ptid_t ptid, int step,
- enum target_signal siggnal);
-
-static ptid_t mips_wait (ptid_t ptid,
- struct target_waitstatus *status);
+static void mips_detach (struct target_ops *ops, char *args, int from_tty);
static int mips_map_regno (struct gdbarch *, int);
-static void mips_fetch_registers (struct regcache *regcache, int regno);
+static void mips_set_register (int regno, ULONGEST value);
static void mips_prepare_to_store (struct regcache *regcache);
-static void mips_store_registers (struct regcache *regcache, int regno);
-
-static unsigned int mips_fetch_word (CORE_ADDR addr);
+static int mips_fetch_word (CORE_ADDR addr, unsigned int *valp);
static int mips_store_word (CORE_ADDR addr, unsigned int value,
- char *old_contents);
+ int *old_contents);
static int mips_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len,
int write,
static void mips_files_info (struct target_ops *ignore);
-static void mips_mourn_inferior (void);
+static void mips_mourn_inferior (struct target_ops *ops);
static int pmon_makeb64 (unsigned long v, char *p, int n, int *chksum);
extern struct target_ops mips_ops;
extern struct target_ops pmon_ops;
extern struct target_ops ddb_ops;
+extern struct target_ops rockhopper_ops;
\f/* *INDENT-OFF* */
/* The MIPS remote debugging interface is built on top of a simple
packet protocol. Each packet is organized as follows:
These are initialized with code in _initialize_remote_mips instead
of static initializers, to make it easier to extend the target_ops
vector later. */
-struct target_ops mips_ops, pmon_ops, ddb_ops, lsi_ops;
+struct target_ops mips_ops, pmon_ops, ddb_ops, rockhopper_ops, lsi_ops;
enum mips_monitor_type
{
MON_PMON, /* 3.0.83 [COGENT,EB,FP,NET] Algorithmics Ltd. Nov 9 1995 17:19:50 */
MON_DDB, /* 2.7.473 [DDBVR4300,EL,FP,NET] Risq Modular Systems, Thu Jun 6 09:28:40 PDT 1996 */
MON_LSI, /* 4.3.12 [EB,FP], LSI LOGIC Corp. Tue Feb 25 13:22:14 1997 */
+ MON_ROCKHOPPER,
/* Last and unused value, for sizing vectors, etc. */
MON_LAST
};
of warnings returned by PMON when hardware breakpoints are used. */
static int monitor_warnings;
+/* This is the ptid we use while we're connected to the remote. Its
+ value is arbitrary, as the remote-mips target doesn't have a notion of
+ processes or threads, but we need something non-null to place in
+ inferior_ptid. */
+static ptid_t remote_mips_ptid;
+
+/* Close any ports which might be open. Reset certain globals indicating
+ the state of those ports. */
static void
close_ports (void)
all hell to break loose--the rest of GDB will tend to get left in an
inconsistent state. */
-static NORETURN void
+static void ATTRIBUTE_NORETURN
mips_error (char *string,...)
{
va_list args;
close_ports ();
printf_unfiltered ("Ending remote MIPS debugging.\n");
- target_mourn_inferior ();
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ target_mourn_inferior ();
deprecated_throw_reason (RETURN_ERROR);
}
}
+/* Read P as a hex value. Return true if every character made sense,
+ storing the result in *RESULT. Leave *RESULT unchanged otherwise. */
+
+static int
+read_hex_value (const char *p, ULONGEST *result)
+{
+ ULONGEST retval;
+
+ retval = 0;
+ while (*p != 0)
+ {
+ retval <<= 4;
+ if (*p >= '0' && *p <= '9')
+ retval |= *p - '0';
+ else if (*p >= 'A' && *p <= 'F')
+ retval |= *p - 'A' + 10;
+ else if (*p >= 'a' && *p <= 'f')
+ retval |= *p - 'a' + 10;
+ else
+ return 0;
+ p++;
+ }
+ *result = retval;
+ return 1;
+}
+
+
/* Wait until STRING shows up in mips_desc. Returns 1 if successful, else 0 if
timed out. TIMEOUT specifies timeout value in seconds.
*/
static int state = 0;
int mips_monitor_prompt_len = strlen (mips_monitor_prompt);
- {
+ { /* FIXME this whole block is dead code! */
int i;
i = timeout;
int timeout,
char *buff)
{
+ int addr_size = gdbarch_addr_bit (target_gdbarch) / 8;
char myBuff[DATA_MAXLEN + 1];
+ char response_string[17];
int len;
int rpid;
char rcmd;
int rerrflg;
- unsigned long rresponse;
+ ULONGEST rresponse;
if (buff == (char *) NULL)
buff = myBuff;
if (mips_need_reply)
internal_error (__FILE__, __LINE__,
_("mips_request: Trying to send command before reply"));
- sprintf (buff, "0x0 %c 0x%s 0x%s", cmd, paddr_nz (addr), paddr_nz (data));
+ /* 'T' sets a register to a 64-bit value, so make sure we use
+ the right conversion function. */
+ if (cmd == 'T')
+ sprintf (buff, "0x0 %c 0x%s 0x%s", cmd,
+ phex_nz (addr, addr_size), phex_nz (data, 8));
+ else
+ sprintf (buff, "0x0 %c 0x%s 0x%s", cmd,
+ phex_nz (addr, addr_size), phex_nz (data, addr_size));
+
mips_send_packet (buff, 1);
mips_need_reply = 1;
}
len = mips_receive_packet (buff, 1, timeout);
buff[len] = '\0';
- if (sscanf (buff, "0x%x %c 0x%x 0x%lx",
- &rpid, &rcmd, &rerrflg, &rresponse) != 4
+ if (sscanf (buff, "0x%x %c 0x%x 0x%16s",
+ &rpid, &rcmd, &rerrflg, response_string) != 4
+ || !read_hex_value (response_string, &rresponse)
|| (cmd != '\0' && rcmd != cmd))
mips_error ("Bad response from remote board");
return rresponse;
}
+/* Cleanup associated with mips_initialize(). */
+
static void
mips_initialize_cleanups (void *arg)
{
mips_initializing = 0;
}
+/* Cleanup associated with mips_exit_debug(). */
+
static void
mips_exit_cleanups (void *arg)
{
mips_exiting = 0;
}
+/* Send a command and wait for that command to be echoed back. Wait,
+ too, for the following prompt. */
+
static void
mips_send_command (const char *cmd, int prompt)
{
}
/* Enter remote (dbx) debug mode: */
+
static void
mips_enter_debug (void)
{
{
char buff[DATA_MAXLEN + 1];
+
if (mips_receive_packet (buff, 1, 3) < 0)
mips_error ("Failed to initialize (didn't receive packet).");
}
}
/* Exit remote (dbx) debug mode, returning to the monitor prompt: */
+
static int
mips_exit_debug (void)
{
mips_exiting = 1;
- if (mips_monitor != MON_IDT)
+ if (mips_monitor != MON_IDT && mips_monitor != MON_ROCKHOPPER)
{
/* The DDB (NEC) and MiniRISC (LSI) versions of PMON exit immediately,
so we do not get a reply to this command: */
}
/* Open a connection to the remote board. */
+
static void
common_open (struct target_ops *ops, char *name, int from_tty,
enum mips_monitor_type new_monitor,
/* Parse the serial port name, the optional TFTP name, and the
optional local TFTP name. */
- if ((argv = buildargv (name)) == NULL)
- nomem (0);
+ argv = gdb_buildargv (name);
make_cleanup_freeargv (argv);
serial_port_name = xstrdup (argv[0]);
/* Switch to using remote target now. */
push_target (ops);
- /* FIXME: Should we call start_remote here? */
+ inferior_ptid = remote_mips_ptid;
+ inferior_appeared (current_inferior (), ptid_get_pid (inferior_ptid));
+ add_thread_silent (inferior_ptid);
/* Try to figure out the processor model if possible. */
deprecated_mips_set_processor_regs_hack ();
reinit_frame_cache ();
registers_changed ();
- stop_pc = read_pc ();
+ stop_pc = regcache_read_pc (get_current_regcache ());
print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
xfree (serial_port_name);
}
+/* Open a connection to an IDT board. */
+
static void
mips_open (char *name, int from_tty)
{
const char *monitor_prompt = NULL;
- if (gdbarch_bfd_arch_info (current_gdbarch) != NULL
- && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_mips)
+ if (gdbarch_bfd_arch_info (target_gdbarch) != NULL
+ && gdbarch_bfd_arch_info (target_gdbarch)->arch == bfd_arch_mips)
{
- switch (gdbarch_bfd_arch_info (current_gdbarch)->mach)
+ switch (gdbarch_bfd_arch_info (target_gdbarch)->mach)
{
case bfd_mach_mips4100:
case bfd_mach_mips4300:
common_open (&mips_ops, name, from_tty, MON_IDT, monitor_prompt);
}
+/* Open a connection to a PMON board. */
+
static void
pmon_open (char *name, int from_tty)
{
common_open (&pmon_ops, name, from_tty, MON_PMON, "PMON> ");
}
+/* Open a connection to a DDB board. */
+
static void
ddb_open (char *name, int from_tty)
{
common_open (&ddb_ops, name, from_tty, MON_DDB, "NEC010>");
}
+/* Open a connection to a rockhopper board. */
+
+static void
+rockhopper_open (char *name, int from_tty)
+{
+ common_open (&rockhopper_ops, name, from_tty, MON_ROCKHOPPER, "NEC01>");
+}
+
+/* Open a connection to an LSI board. */
+
static void
lsi_open (char *name, int from_tty)
{
close_ports ();
}
+
+ generic_mourn_inferior ();
}
/* Detach from the remote board. */
static void
-mips_detach (char *args, int from_tty)
+mips_detach (struct target_ops *ops, char *args, int from_tty)
{
if (args)
error ("Argument given to \"detach\" when remotely debugging.");
where PMON does return a reply. */
static void
-mips_resume (ptid_t ptid, int step, enum target_signal siggnal)
+mips_resume (struct target_ops *ops,
+ ptid_t ptid, int step, enum target_signal siggnal)
{
int err;
/* Return the signal corresponding to SIG, where SIG is the number which
the MIPS protocol uses for the signal. */
+
static enum target_signal
mips_signal_from_protocol (int sig)
{
return (enum target_signal) sig;
}
+/* Set the register designated by REGNO to the value designated by VALUE. */
+
+static void
+mips_set_register (int regno, ULONGEST value)
+{
+ char buf[MAX_REGISTER_SIZE];
+ struct regcache *regcache = get_current_regcache ();
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ /* We got the number the register holds, but gdb expects to see a
+ value in the target byte ordering. */
+
+ if (mips_monitor != MON_ROCKHOPPER
+ && (regno == mips_regnum (gdbarch)->pc || regno < 32))
+ /* Some 64-bit boards have monitors that only send the bottom 32 bits.
+ In such cases we can only really debug 32-bit code properly so,
+ when reading a GPR or the PC, assume that the full 64-bit
+ value is the sign extension of the lower 32 bits. */
+ store_signed_integer (buf, register_size (gdbarch, regno), byte_order,
+ value);
+ else
+ store_unsigned_integer (buf, register_size (gdbarch, regno), byte_order,
+ value);
+
+ regcache_raw_supply (regcache, regno, buf);
+}
+
/* Wait until the remote stops, and return a wait status. */
static ptid_t
-mips_wait (ptid_t ptid, struct target_waitstatus *status)
+mips_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status, int options)
{
int rstatus;
int err;
char buff[DATA_MAXLEN];
- int rpc, rfp, rsp;
- char flags[20];
+ ULONGEST rpc, rfp, rsp;
+ char pc_string[17], fp_string[17], sp_string[17], flags[20];
int nfields;
int i;
/* See if we got back extended status. If so, pick out the pc, fp, sp, etc... */
- nfields = sscanf (buff, "0x%*x %*c 0x%*x 0x%*x 0x%x 0x%x 0x%x 0x%*x %s",
- &rpc, &rfp, &rsp, flags);
- if (nfields >= 3)
+ nfields = sscanf (buff, "0x%*x %*c 0x%*x 0x%*x 0x%16s 0x%16s 0x%16s 0x%*x %s",
+ pc_string, fp_string, sp_string, flags);
+ if (nfields >= 3
+ && read_hex_value (pc_string, &rpc)
+ && read_hex_value (fp_string, &rfp)
+ && read_hex_value (sp_string, &rsp))
{
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- char buf[MAX_REGISTER_SIZE];
-
- store_unsigned_integer (buf,
- register_size
- (gdbarch, gdbarch_pc_regnum (gdbarch)), rpc);
- regcache_raw_supply (regcache, gdbarch_pc_regnum (gdbarch), buf);
- store_unsigned_integer
- (buf, register_size (gdbarch, gdbarch_pc_regnum (gdbarch)), rfp);
- regcache_raw_supply (regcache, 30, buf); /* This register they are avoiding and so it is unnamed */
-
- store_unsigned_integer (buf, register_size (gdbarch,
- gdbarch_sp_regnum (gdbarch)), rsp);
- regcache_raw_supply (regcache, gdbarch_sp_regnum (gdbarch), buf);
-
- store_unsigned_integer (buf,
- register_size (gdbarch,
- gdbarch_deprecated_fp_regnum
- (gdbarch)),
- 0);
- regcache_raw_supply (regcache,
- gdbarch_deprecated_fp_regnum (gdbarch), buf);
+ mips_set_register (gdbarch_pc_regnum (gdbarch), rpc);
+ mips_set_register (30, rfp);
+ mips_set_register (gdbarch_sp_regnum (gdbarch), rsp);
if (nfields == 9)
{
fetch breakpoint, not a data watchpoint. FIXME when PMON
provides some way to tell us what type of breakpoint it is. */
int i;
- CORE_ADDR pc = read_pc ();
+ CORE_ADDR pc = regcache_read_pc (get_current_regcache ());
hit_watchpoint = 1;
for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
{
char *func_name;
CORE_ADDR func_start;
- CORE_ADDR pc = read_pc ();
+ CORE_ADDR pc = regcache_read_pc (get_current_regcache ());
find_pc_partial_function (pc, &func_name, &func_start, NULL);
if (func_name != NULL && strcmp (func_name, "_exit") == 0
/* Fetch the remote registers. */
static void
-mips_fetch_registers (struct regcache *regcache, int regno)
+mips_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- unsigned LONGEST val;
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ ULONGEST val;
int err;
if (regno == -1)
{
for (regno = 0; regno < gdbarch_num_regs (gdbarch); regno++)
- mips_fetch_registers (regcache, regno);
+ mips_fetch_registers (ops, regcache, regno);
return;
}
/* If PMON doesn't support this register, don't waste serial
bandwidth trying to read it. */
int pmon_reg = mips_map_regno (gdbarch, regno);
+
if (regno != 0 && pmon_reg == 0)
val = 0;
else
/* Unfortunately the PMON version in the Vr4300 board has been
compiled without the 64bit register access commands. This
means we cannot get hold of the full register width. */
- if (mips_monitor == MON_DDB)
- val = (unsigned) mips_request ('t', pmon_reg, 0,
- &err, mips_receive_wait, NULL);
+ if (mips_monitor == MON_DDB || mips_monitor == MON_ROCKHOPPER)
+ val = mips_request ('t', pmon_reg, 0,
+ &err, mips_receive_wait, NULL);
else
val = mips_request ('r', pmon_reg, 0,
&err, mips_receive_wait, NULL);
}
}
- {
- char buf[MAX_REGISTER_SIZE];
-
- /* We got the number the register holds, but gdb expects to see a
- value in the target byte ordering. */
- store_unsigned_integer (buf, register_size (gdbarch, regno), val);
- regcache_raw_supply (regcache, regno, buf);
- }
+ mips_set_register (regno, val);
}
/* Prepare to store registers. The MIPS protocol can store individual
/* Store remote register(s). */
static void
-mips_store_registers (struct regcache *regcache, int regno)
+mips_store_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
ULONGEST val;
if (regno == -1)
{
for (regno = 0; regno < gdbarch_num_regs (gdbarch); regno++)
- mips_store_registers (regcache, regno);
+ mips_store_registers (ops, regcache, regno);
return;
}
regcache_cooked_read_unsigned (regcache, regno, &val);
- mips_request ('R', mips_map_regno (gdbarch, regno), val,
+ mips_request (mips_monitor == MON_ROCKHOPPER ? 'T' : 'R',
+ mips_map_regno (gdbarch, regno),
+ val,
&err, mips_receive_wait, NULL);
if (err)
mips_error ("Can't write register %d: %s", regno, safe_strerror (errno));
}
-/* Fetch a word from the target board. */
+/* Fetch a word from the target board. Return word fetched in location
+ addressed by VALP. Return 0 when successful; return positive error
+ code when not. */
-static unsigned int
-mips_fetch_word (CORE_ADDR addr)
+static int
+mips_fetch_word (CORE_ADDR addr, unsigned int *valp)
{
- unsigned int val;
int err;
- val = mips_request ('d', addr, 0, &err, mips_receive_wait, NULL);
+ *valp = mips_request ('d', addr, 0, &err, mips_receive_wait, NULL);
if (err)
{
/* Data space failed; try instruction space. */
- val = mips_request ('i', addr, 0, &err,
- mips_receive_wait, NULL);
- if (err)
- mips_error ("Can't read address 0x%s: %s",
- paddr_nz (addr), safe_strerror (errno));
+ *valp = mips_request ('i', addr, 0, &err,
+ mips_receive_wait, NULL);
}
- return val;
+ return err;
}
/* Store a word to the target board. Returns errno code or zero for
/* FIXME! make sure only 32-bit quantities get stored! */
static int
-mips_store_word (CORE_ADDR addr, unsigned int val, char *old_contents)
+mips_store_word (CORE_ADDR addr, unsigned int val, int *old_contents)
{
int err;
unsigned int oldcontents;
return errno;
}
if (old_contents != NULL)
- store_unsigned_integer (old_contents, 4, oldcontents);
+ *old_contents = oldcontents;
return 0;
}
mips_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
struct mem_attrib *attrib, struct target_ops *target)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
int i;
CORE_ADDR addr;
int count;
/* Fill start and end extra bytes of buffer with existing data. */
if (addr != memaddr || len < 4)
{
+ unsigned int val;
+
+ if (mips_fetch_word (addr, &val))
+ return 0;
+
/* Need part of initial word -- fetch it. */
- store_unsigned_integer (&buffer[0], 4, mips_fetch_word (addr));
+ store_unsigned_integer (&buffer[0], 4, byte_order, val);
}
if (count > 1)
{
+ unsigned int val;
+
/* Need part of last word -- fetch it. FIXME: we do this even
if we don't need it. */
- store_unsigned_integer (&buffer[(count - 1) * 4], 4,
- mips_fetch_word (addr + (count - 1) * 4));
+ if (mips_fetch_word (addr + (count - 1) * 4, &val))
+ return 0;
+
+ store_unsigned_integer (&buffer[(count - 1) * 4], 4, byte_order, val);
}
/* Copy data to be written over corresponding part of buffer */
for (i = 0; i < count; i++, addr += 4)
{
- status = mips_store_word (addr,
- extract_unsigned_integer (&buffer[i * 4], 4),
- NULL);
+ int word;
+
+ word = extract_unsigned_integer (&buffer[i * 4], 4, byte_order);
+ status = mips_store_word (addr, word, NULL);
/* Report each kilobyte (we download 32-bit words at a time) */
if (i % 256 == 255)
{
/* Read all the longwords */
for (i = 0; i < count; i++, addr += 4)
{
- store_unsigned_integer (&buffer[i * 4], 4, mips_fetch_word (addr));
+ unsigned int val;
+
+ if (mips_fetch_word (addr, &val))
+ return 0;
+
+ store_unsigned_integer (&buffer[i * 4], 4, byte_order, val);
QUIT;
}
right port, we could interrupt the process with a break signal. */
static void
-mips_kill (void)
+mips_kill (struct target_ops *ops)
{
if (!mips_wait_flag)
- return;
+ {
+ target_mourn_inferior ();
+ return;
+ }
interrupt_count++;
target_terminal_ours ();
- if (query ("Interrupted while waiting for the program.\n\
-Give up (and stop debugging it)? "))
+ if (query (_("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? ")))
{
/* Clean up in such a way that mips_close won't try to talk to the
board (it almost surely won't work since we weren't able to talk to
serial_send_break (mips_desc);
+ target_mourn_inferior ();
+
#if 0
if (mips_is_open)
{
/* Start running on the target board. */
static void
-mips_create_inferior (char *execfile, char *args, char **env, int from_tty)
+mips_create_inferior (struct target_ops *ops, char *execfile,
+ char *args, char **env, int from_tty)
{
CORE_ADDR entry_pt;
init_wait_for_inferior ();
- /* FIXME: Should we set inferior_ptid here? */
-
- write_pc (entry_pt);
+ regcache_write_pc (get_current_regcache (), entry_pt);
}
-/* Clean up after a process. Actually nothing to do. */
+/* Clean up after a process. The bulk of the work is done in mips_close(),
+ which is called when unpushing the target. */
static void
-mips_mourn_inferior (void)
+mips_mourn_inferior (struct target_ops *ops)
{
if (current_ops != NULL)
unpush_target (current_ops);
- generic_mourn_inferior ();
}
\f
/* We can write a breakpoint and read the shadow contents in one
target contents. */
static int
-mips_insert_breakpoint (struct bp_target_info *bp_tgt)
+mips_insert_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
if (monitor_supports_breakpoints)
return mips_set_breakpoint (bp_tgt->placed_address, MIPS_INSN32_SIZE,
BREAK_FETCH);
else
- return memory_insert_breakpoint (bp_tgt);
+ return memory_insert_breakpoint (gdbarch, bp_tgt);
}
+/* Remove a breakpoint. */
+
static int
-mips_remove_breakpoint (struct bp_target_info *bp_tgt)
+mips_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
if (monitor_supports_breakpoints)
return mips_clear_breakpoint (bp_tgt->placed_address, MIPS_INSN32_SIZE,
BREAK_FETCH);
else
- return memory_remove_breakpoint (bp_tgt);
+ return memory_remove_breakpoint (gdbarch, bp_tgt);
}
/* Tell whether this target can support a hardware breakpoint. CNT
is the number of hardware breakpoints already installed. This
- implements the TARGET_CAN_USE_HARDWARE_WATCHPOINT macro. */
+ implements the target_can_use_hardware_watchpoint macro. */
int
mips_can_use_watchpoint (int type, int cnt, int othertype)
return 0;
}
+/* Remove a watchpoint. */
+
int
mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
{
return 0;
}
+/* Test to see if a watchpoint has been hit. Return 1 if so; return 0,
+ if not. */
+
int
mips_stopped_by_watchpoint (void)
{
mips_check_lsi_error (CORE_ADDR addr, int rerrflg)
{
struct lsi_error *err;
- char *saddr = paddr_nz (addr); /* printable address string */
+ const char *saddr = paddress (target_gdbarch, addr);
if (rerrflg == 0) /* no error */
return 0;
if (monitor_warnings)
{
int found = 0;
+
for (err = lsi_warning_table; err->code != 0; err++)
{
if ((err->code & rerrflg) == err->code)
{
found = 1;
fprintf_unfiltered (gdb_stderr, "\
-mips_common_breakpoint (0x%s): Warning: %s\n",
+mips_common_breakpoint (%s): Warning: %s\n",
saddr,
err->string);
}
}
if (!found)
fprintf_unfiltered (gdb_stderr, "\
-mips_common_breakpoint (0x%s): Unknown warning: 0x%x\n",
+mips_common_breakpoint (%s): Unknown warning: 0x%x\n",
saddr,
rerrflg);
}
if ((err->code & rerrflg) == err->code)
{
fprintf_unfiltered (gdb_stderr, "\
-mips_common_breakpoint (0x%s): Error: %s\n",
+mips_common_breakpoint (%s): Error: %s\n",
saddr,
err->string);
return 1;
}
}
fprintf_unfiltered (gdb_stderr, "\
-mips_common_breakpoint (0x%s): Unknown error: 0x%x\n",
+mips_common_breakpoint (%s): Unknown error: 0x%x\n",
saddr,
rerrflg);
return 1;
static int
mips_common_breakpoint (int set, CORE_ADDR addr, int len, enum break_type type)
{
+ int addr_size = gdbarch_addr_bit (target_gdbarch) / 8;
char buf[DATA_MAXLEN + 1];
char cmd, rcmd;
int rpid, rerrflg, rresponse, rlen;
int nfields;
- addr = gdbarch_addr_bits_remove (current_gdbarch, addr);
+ addr = gdbarch_addr_bits_remove (target_gdbarch, addr);
if (mips_monitor == MON_LSI)
{
{
warning ("\
mips_common_breakpoint: Attempt to clear bogus breakpoint at %s\n",
- paddr_nz (addr));
+ paddress (target_gdbarch, addr));
return 1;
}
if (type == BREAK_FETCH) /* instruction breakpoint */
{
cmd = 'B';
- sprintf (buf, "0x0 B 0x%s 0x0", paddr_nz (addr));
+ sprintf (buf, "0x0 B 0x%s 0x0", phex_nz (addr, addr_size));
}
else
/* watchpoint */
{
cmd = 'A';
- sprintf (buf, "0x0 A 0x%s 0x%x 0x%s", paddr_nz (addr),
- type == BREAK_READ ? 1 : (type == BREAK_WRITE ? 2 : 3),
- paddr_nz (addr + len - 1));
+ sprintf (buf, "0x0 A 0x%s 0x%x 0x%s",
+ phex_nz (addr, addr_size),
+ type == BREAK_READ ? 1 : (type == BREAK_WRITE ? 2 : 3),
+ phex_nz (addr + len - 1, addr_size));
}
mips_send_packet (buf, 1);
if (set) /* set a breakpoint */
{
char *flags;
+
switch (type)
{
case BREAK_WRITE: /* write */
}
cmd = 'B';
- sprintf (buf, "0x0 B 0x%s 0x%s %s", paddr_nz (addr),
- paddr_nz (mask), flags);
+ sprintf (buf, "0x0 B 0x%s 0x%s %s", phex_nz (addr, addr_size),
+ phex_nz (mask, addr_size), flags);
}
else
{
cmd = 'b';
- sprintf (buf, "0x0 b 0x%s", paddr_nz (addr));
+ sprintf (buf, "0x0 b 0x%s", phex_nz (addr, addr_size));
}
mips_send_packet (buf, 1);
rresponse = rerrflg;
if (rresponse != 22) /* invalid argument */
fprintf_unfiltered (gdb_stderr, "\
-mips_common_breakpoint (0x%s): Got error: 0x%x\n",
- paddr_nz (addr), rresponse);
+mips_common_breakpoint (%s): Got error: 0x%x\n",
+ paddress (target_gdbarch, addr), rresponse);
return 1;
}
}
return 0;
}
\f
+/* Send one S record as specified by SREC of length LEN, starting
+ at ADDR. Note, however, that ADDR is not used except to provide
+ a useful message to the user in the event that a NACK is received
+ from the board. */
+
static void
send_srec (char *srec, int len, CORE_ADDR addr)
{
case 0x6: /* ACK */
return;
case 0x15: /* NACK */
- fprintf_unfiltered (gdb_stderr, "Download got a NACK at byte %s! Retrying.\n", paddr_u (addr));
+ fprintf_unfiltered (gdb_stderr, "Download got a NACK at byte %s! Retrying.\n",
+ paddress (target_gdbarch, addr));
continue;
default:
error ("Download got unexpected ack char: 0x%x, retrying.\n", ch);
at a time (range 0..63). Keep a checksum if required (passed
pointer non-NULL). The function returns the number of encoded
characters written into the buffer. */
+
static int
pmon_makeb64 (unsigned long v, char *p, int n, int *chksum)
{
/* Shorthand function (that could be in-lined) to output the zero-fill
escape sequence into the data stream. */
+
static int
pmon_zeroset (int recsize, char **buff, int *amount, unsigned int *chksum)
{
return (recsize + count + 2);
}
+/* Add the checksum specified by *VALUE to end of the record under
+ construction. *BUF specifies the location at which to begin
+ writing characters comprising the checksum information. RECSIZE
+ specifies the size of the record constructed thus far. (A trailing
+ NUL character may be present in the buffer holding the record, but
+ the record size does not include this character.)
+
+ Return the total size of the record after adding the checksum escape,
+ the checksum itself, and the trailing newline.
+
+ The checksum specified by *VALUE is zeroed out prior to returning.
+ Additionally, *BUF is updated to refer to the location just beyond
+ the record elements added by this call. */
+
static int
pmon_checkset (int recsize, char **buff, int *value)
{
/* NOTE: This constant depends on the monitor being used. This value
is for PMON 5.x on the Cogent Vr4300 board. */
+/* Create a FastLoad format record.
+
+ *OUTBUF is the buffer into which a FastLoad formatted record is
+ written. On return, the pointer position represented by *OUTBUF
+ is updated to point at the end of the data, i.e. the next position
+ in the buffer that may be written. No attempt is made to NUL-
+ terminate this portion of the record written to the buffer.
+
+ INBUF contains the binary input data from which the FastLoad
+ formatted record will be built. *INPTR is an index into this
+ buffer. *INPTR is updated as the input is consumed. Thus, on
+ return, the caller has access to the position of the next input
+ byte yet to be processed. INAMOUNT is the size, in bytes, of the
+ input data.
+
+ *RECSIZE will be written with the size of the record written to the
+ output buffer prior to returning. This size does not include a
+ NUL-termination byte as none is written to the output buffer.
+
+ *CSUM is the output buffer checksum. It is updated as data is
+ written to the output buffer.
+
+ *ZEROFILL is the current number of 3-byte zero sequences that have
+ been encountered. It is both an input and an output to this
+ function. */
+
static void
pmon_make_fastrec (char **outbuf, unsigned char *inbuf, int *inptr,
int inamount, int *recsize, unsigned int *csum,
else
{
unsigned int value = ((inbuf[*inptr + 0] << 16) | (inbuf[*inptr + 1] << 8) | inbuf[*inptr + 2]);
+
/* Simple check for zero data. TODO: A better check would be
to check the last, and then the middle byte for being zero
(if the first byte is not). We could then check for
return;
}
+/* Attempt to read an ACK. If an ACK is not read in a timely manner,
+ output the message specified by MESG. Return -1 for failure, 0
+ for success. */
+
static int
pmon_check_ack (char *mesg)
{
}
}
+/* Look for the string specified by STRING sent from the target board
+ during a download operation. If the string in question is not
+ seen, output an error message, remove the temporary file, if
+ appropriate, and return 0. Otherwise, return 1 to indicate
+ success. */
+
static int
mips_expect_download (char *string)
{
return 1;
}
+/* Look for messages from the target board associated with the entry
+ address.
+
+ NOTE: This function doesn't indicate success or failure, so we
+ have no way to determine whether or not the output from the board
+ was correctly seen. However, given that other items are checked
+ after this, it seems unlikely that those checks will pass if this
+ check doesn't first (silently) pass. */
+
static void
pmon_check_entry_address (char *entry_address, int final)
{
char hexnumber[9]; /* includes '\0' space */
+
mips_expect_timeout (entry_address, tftp_in_use ? 15 : remote_timeout);
sprintf (hexnumber, "%x", final);
mips_expect (hexnumber);
mips_expect ("\r\n");
}
+/* Look for messages from the target board showing the total number of
+ bytes downloaded to the board. Output 1 for success if the tail
+ end of the message was read correctly, 0 otherwise. */
+
static int
pmon_check_total (int bintotal)
{
char hexnumber[9]; /* includes '\0' space */
+
mips_expect ("\r\ntotal = 0x");
sprintf (hexnumber, "%x", bintotal);
mips_expect (hexnumber);
return mips_expect_download (" bytes\r\n");
}
+/* Look for the termination messages associated with the end of
+ a download to the board.
+
+ Also, when `tftp_in_use' is set, issue the load command to the
+ board causing the file to be transferred. (This is done prior
+ to looking for the above mentioned termination messages.) */
+
static void
pmon_end_download (int final, int bintotal)
{
chmod (tftp_localname, stbuf.st_mode | S_IROTH);
/* Must reinitialize the board to prevent PMON from crashing. */
- mips_send_command ("initEther\r", -1);
+ if (mips_monitor != MON_ROCKHOPPER)
+ mips_send_command ("initEther\r", -1);
/* Send the load command. */
cmd = xmalloc (strlen (load_cmd_prefix) + strlen (tftp_name) + 2);
if (!pmon_check_total (bintotal))
return;
break;
+ case MON_ROCKHOPPER:
+ if (!pmon_check_total (bintotal))
+ return;
+ pmon_check_entry_address ("Entry Address = ", final);
+ break;
default:
pmon_check_entry_address ("Entry Address = ", final);
pmon_check_ack ("termination");
remove (tftp_localname); /* Remove temporary file */
}
+/* Write the buffer specified by BUFFER of length LENGTH to either
+ the board or the temporary file that'll eventually be transferred
+ to the board. */
+
static void
pmon_download (char *buffer, int length)
{
serial_write (udp_in_use ? udp_desc : mips_desc, buffer, length);
}
+/* Open object or executable file, FILE, and send it to the board
+ using the FastLoad format. */
+
static void
pmon_load_fast (char *file)
{
static void
mips_load (char *file, int from_tty)
{
+ struct regcache *regcache;
+
/* Get the board out of remote debugging mode. */
if (mips_exit_debug ())
error ("mips_load: Couldn't get into monitor mode.");
mips_initialize ();
/* Finally, make the PC point at the start address */
+ regcache = get_current_regcache ();
if (mips_monitor != MON_IDT)
{
/* Work around problem where PMON monitor updates the PC after a load
to a different value than GDB thinks it has. The following ensures
- that the write_pc() WILL update the PC value: */
- struct regcache *regcache = get_current_regcache ();
- regcache_set_valid_p (regcache,
- gdbarch_pc_regnum (get_regcache_arch (regcache)),
- 0);
+ that the regcache_write_pc() WILL update the PC value: */
+ regcache_invalidate (regcache,
+ mips_regnum (get_regcache_arch (regcache))->pc);
}
if (exec_bfd)
- write_pc (bfd_get_start_address (exec_bfd));
-
- inferior_ptid = null_ptid; /* No process now */
+ regcache_write_pc (regcache, bfd_get_start_address (exec_bfd));
+}
-/* This is necessary because many things were based on the PC at the time that
- we attached to the monitor, which is no longer valid now that we have loaded
- new code (and just changed the PC). Another way to do this might be to call
- normal_stop, except that the stack may not be valid, and things would get
- horribly confused... */
+/* Check to see if a thread is still alive. */
+
+static int
+mips_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+ if (ptid_equal (ptid, remote_mips_ptid))
+ /* The monitor's task is always alive. */
+ return 1;
- clear_symtab_users ();
+ return 0;
}
+/* Convert a thread ID to a string. Returns the string in a static
+ buffer. */
+
+static char *
+mips_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+ static char buf[64];
+
+ if (ptid_equal (ptid, remote_mips_ptid))
+ {
+ xsnprintf (buf, sizeof buf, "Thread <main>");
+ return buf;
+ }
+
+ return normal_pid_to_str (ptid);
+}
/* Pass the command argument as a packet to PMON verbatim. */
\f
extern initialize_file_ftype _initialize_remote_mips; /* -Wmissing-prototypes */
+/* Initialize mips_ops, lsi_ops, ddb_ops, pmon_ops, and rockhopper_ops.
+ Create target specific commands and perform other initializations
+ specific to this file. */
+
void
_initialize_remote_mips (void)
{
mips_ops.to_load = mips_load;
mips_ops.to_create_inferior = mips_create_inferior;
mips_ops.to_mourn_inferior = mips_mourn_inferior;
+ mips_ops.to_thread_alive = mips_thread_alive;
+ mips_ops.to_pid_to_str = mips_pid_to_str;
mips_ops.to_log_command = serial_log_command;
mips_ops.to_stratum = process_stratum;
- mips_ops.to_has_all_memory = 1;
- mips_ops.to_has_memory = 1;
- mips_ops.to_has_stack = 1;
- mips_ops.to_has_registers = 1;
- mips_ops.to_has_execution = 1;
+ mips_ops.to_has_all_memory = default_child_has_all_memory;
+ mips_ops.to_has_memory = default_child_has_memory;
+ mips_ops.to_has_stack = default_child_has_stack;
+ mips_ops.to_has_registers = default_child_has_registers;
+ mips_ops.to_has_execution = default_child_has_execution;
mips_ops.to_magic = OPS_MAGIC;
/* Copy the common fields to all four target vectors. */
- pmon_ops = ddb_ops = lsi_ops = mips_ops;
+ rockhopper_ops = pmon_ops = ddb_ops = lsi_ops = mips_ops;
/* Initialize target-specific fields in the target vectors. */
mips_ops.to_shortname = "mips";
ddb_ops.to_open = ddb_open;
ddb_ops.to_wait = mips_wait;
+ rockhopper_ops.to_shortname = "rockhopper";
+ rockhopper_ops.to_doc = ddb_ops.to_doc;
+ rockhopper_ops.to_open = rockhopper_open;
+ rockhopper_ops.to_wait = mips_wait;
+
lsi_ops.to_shortname = "lsi";
lsi_ops.to_doc = pmon_ops.to_doc;
lsi_ops.to_open = lsi_open;
add_target (&pmon_ops);
add_target (&ddb_ops);
add_target (&lsi_ops);
+ add_target (&rockhopper_ops);
add_setshow_zinteger_cmd ("timeout", no_class, &mips_receive_wait, _("\
Set timeout in seconds for remote MIPS serial I/O."), _("\
NULL,
NULL, /* FIXME: i18n: */
&setlist, &showlist);
+ remote_mips_ptid = ptid_build (42000, 0, 42000);
}