#include "defs.h"
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "serial.h"
#include "target.h"
#include "exceptions.h"
#include "remote-utils.h"
#include "gdb_string.h"
#include "gdb_stat.h"
#include "regcache.h"
#include <ctype.h>
#include "mips-tdep.h"
#include "inlining.h"
enum break_type
{
BREAK_WRITE,
BREAK_READ,
BREAK_ACCESS,
BREAK_FETCH,
BREAK_UNUSED
};
static int mips_readchar (int timeout);
static int mips_receive_header (unsigned char *hdr, int *pgarbage,
int ch, int timeout);
static int mips_receive_trailer (unsigned char *trlr, int *pgarbage,
int *pch, int timeout);
static int mips_cksum (const unsigned char *hdr,
const unsigned char *data, int len);
static void mips_send_packet (const char *s, int get_ack);
static void mips_send_command (const char *cmd, int prompt);
static int mips_receive_packet (char *buff, int throw_error, int timeout);
static ULONGEST mips_request (int cmd, ULONGEST addr, ULONGEST data,
int *perr, int timeout, char *buff);
static void mips_initialize (void);
static void mips_open (char *name, int from_tty);
static void pmon_open (char *name, int from_tty);
static void ddb_open (char *name, int from_tty);
static void lsi_open (char *name, int from_tty);
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 int mips_map_regno (int regno);
static void mips_fetch_registers (int regno);
static void mips_prepare_to_store (void);
static void mips_store_registers (int regno);
static unsigned int mips_fetch_word (CORE_ADDR addr);
static int mips_store_word (CORE_ADDR addr, unsigned int value,
char *old_contents);
static int mips_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
int write,
struct mem_attrib *attrib,
struct target_ops *target);
static void mips_files_info (struct target_ops *ignore);
static void mips_mourn_inferior (void);
static int pmon_makeb64 (unsigned long v, char *p, int n, int *chksum);
static int pmon_zeroset (int recsize, char **buff, int *amount,
unsigned int *chksum);
static int pmon_checkset (int recsize, char **buff, int *value);
static void pmon_make_fastrec (char **outbuf, unsigned char *inbuf,
int *inptr, int inamount, int *recsize,
unsigned int *csum, unsigned int *zerofill);
static int pmon_check_ack (char *mesg);
static void pmon_start_download (void);
static void pmon_end_download (int final, int bintotal);
static void pmon_download (char *buffer, int length);
static void pmon_load_fast (char *file);
static void mips_load (char *file, int from_tty);
static int mips_make_srec (char *buffer, int type, CORE_ADDR memaddr,
unsigned char *myaddr, int len);
static int set_breakpoint (CORE_ADDR addr, int len, enum break_type type);
static int clear_breakpoint (CORE_ADDR addr, int len, enum break_type type);
static int common_breakpoint (int set, CORE_ADDR addr, int len,
enum break_type type);
extern struct target_ops mips_ops;
extern struct target_ops pmon_ops;
extern struct target_ops ddb_ops;
#define SYN '\026'
#define HDR_OFFSET 0x40
#define HDR_INDX_SYN 0
#define HDR_INDX_TYPE_LEN 1
#define HDR_INDX_LEN1 2
#define HDR_INDX_SEQ 3
#define HDR_LENGTH 4
#define TYPE_LEN_DA_BIT 0x20
#define TYPE_LEN_DATA 0
#define TYPE_LEN_ACK TYPE_LEN_DA_BIT
#define HDR_SET_SYN(data, len, seq) (SYN)
#define HDR_SET_TYPE_LEN(data, len, seq) \
(HDR_OFFSET \
+ ((data) ? TYPE_LEN_DATA : TYPE_LEN_ACK) \
+ (((len) >> 6) & 0x1f))
#define HDR_SET_LEN1(data, len, seq) (HDR_OFFSET + ((len) & 0x3f))
#define HDR_SET_SEQ(data, len, seq) (HDR_OFFSET + (seq))
#define HDR_CHECK(ch) (((ch) & HDR_OFFSET) == HDR_OFFSET)
#define HDR_IS_DATA(hdr) \
(((hdr)[HDR_INDX_TYPE_LEN] & TYPE_LEN_DA_BIT) == TYPE_LEN_DATA)
#define HDR_GET_LEN(hdr) \
((((hdr)[HDR_INDX_TYPE_LEN] & 0x1f) << 6) + (((hdr)[HDR_INDX_LEN1] & 0x3f)))
#define HDR_GET_SEQ(hdr) ((unsigned int)(hdr)[HDR_INDX_SEQ] & 0x3f)
#define DATA_MAXLEN 1023
#define TRLR_OFFSET HDR_OFFSET
#define TRLR_INDX_CSUM1 0
#define TRLR_INDX_CSUM2 1
#define TRLR_INDX_CSUM3 2
#define TRLR_LENGTH 3
#define TRLR_SET_CSUM1(cksum) (TRLR_OFFSET + (((cksum) >> 12) & 0x3f))
#define TRLR_SET_CSUM2(cksum) (TRLR_OFFSET + (((cksum) >> 6) & 0x3f))
#define TRLR_SET_CSUM3(cksum) (TRLR_OFFSET + (((cksum) ) & 0x3f))
#define TRLR_CHECK(ch) (((ch) & TRLR_OFFSET) == TRLR_OFFSET)
#define TRLR_GET_CKSUM(trlr) \
((((trlr)[TRLR_INDX_CSUM1] & 0x3f) << 12) \
+ (((trlr)[TRLR_INDX_CSUM2] & 0x3f) << 6) \
+ ((trlr)[TRLR_INDX_CSUM3] & 0x3f))
#define SEQ_MODULOS (64)
#define LOAD_CMD "load -b -s tty0\r"
#define LOAD_CMD_UDP "load -b -s udp\r"
struct target_ops mips_ops, pmon_ops, ddb_ops, lsi_ops;
enum mips_monitor_type
{
MON_IDT,
MON_PMON,
MON_DDB,
MON_LSI,
MON_LAST
};
static enum mips_monitor_type mips_monitor = MON_LAST;
static char *mips_monitor_prompt;
static int mips_is_open;
static struct target_ops *current_ops;
static int mips_initializing;
static int mips_exiting;
static unsigned int mips_send_seq;
static unsigned int mips_receive_seq;
static int mips_retransmit_wait = 3;
static int mips_send_retries = 10;
static int mips_syn_garbage = 10;
static int mips_receive_wait = 5;
static int mips_need_reply = 0;
static struct serial *mips_desc;
static struct serial *udp_desc;
static int udp_in_use;
static char *tftp_name;
static char *tftp_localname;
static int tftp_in_use;
static FILE *tftp_file;
static int interrupt_count;
static int mips_wait_flag = 0;
static int monitor_supports_breakpoints = 0;
#if 0
static DCACHE *mips_dcache;
#endif
static int hit_watchpoint;
#define MAX_LSI_BREAKPOINTS 256
struct lsi_breakpoint_info
{
enum break_type type;
CORE_ADDR addr;
int len;
unsigned long value;
}
lsi_breakpoints[MAX_LSI_BREAKPOINTS];
#define W_WARN 0x100
#define W_MSK 0x101
#define W_VAL 0x102
#define W_QAL 0x104
#define E_ERR 0x200
#define E_BPT 0x200
#define E_RGE 0x201
#define E_QAL 0x202
#define E_OUT 0x203
#define E_NON 0x204
struct lsi_error
{
int code;
char *string;
};
struct lsi_error lsi_warning_table[] =
{
{W_MSK, "Range feature is supported via mask"},
{W_VAL, "Value check is not supported in hardware"},
{W_QAL, "Requested qualifiers are not supported in hardware"},
{0, NULL}
};
struct lsi_error lsi_error_table[] =
{
{E_BPT, "No such breakpoint number"},
{E_RGE, "Range is not supported"},
{E_QAL, "The requested qualifiers can not be used"},
{E_OUT, "Out of hardware resources"},
{E_NON, "Hardware breakpoint not supported"},
{0, NULL}
};
static int monitor_warnings;
static void
close_ports (void)
{
mips_is_open = 0;
serial_close (mips_desc);
if (udp_in_use)
{
serial_close (udp_desc);
udp_in_use = 0;
}
tftp_in_use = 0;
}
static NORETURN void
mips_error (char *string,...)
{
va_list args;
va_start (args, string);
target_terminal_ours ();
wrap_here ("");
gdb_flush (gdb_stdout);
if (error_pre_print)
fputs_filtered (error_pre_print, gdb_stderr);
vfprintf_filtered (gdb_stderr, string, args);
fprintf_filtered (gdb_stderr, "\n");
va_end (args);
gdb_flush (gdb_stderr);
close_ports ();
printf_unfiltered ("Ending remote MIPS debugging.\n");
target_mourn_inferior ();
deprecated_throw_reason (RETURN_ERROR);
}
static void
fputc_readable (int ch, struct ui_file *file)
{
if (ch == '\n')
fputc_unfiltered ('\n', file);
else if (ch == '\r')
fprintf_unfiltered (file, "\\r");
else if (ch < 0x20)
fprintf_unfiltered (file, "^%c", ch + '@');
else if (ch >= 0x7f)
fprintf_unfiltered (file, "[%02x]", ch & 0xff);
else
fputc_unfiltered (ch, file);
}
static void
fputs_readable (const char *string, struct ui_file *file)
{
int c;
while ((c = *string++) != '\0')
fputc_readable (c, file);
}
static int
mips_expect_timeout (const char *string, int timeout)
{
const char *p = string;
if (remote_debug)
{
fprintf_unfiltered (gdb_stdlog, "Expected \"");
fputs_readable (string, gdb_stdlog);
fprintf_unfiltered (gdb_stdlog, "\", got \"");
}
immediate_quit++;
while (1)
{
int c;
c = serial_readchar (mips_desc, timeout);
if (c == SERIAL_TIMEOUT)
{
if (remote_debug)
fprintf_unfiltered (gdb_stdlog, "\": FAIL\n");
return 0;
}
if (remote_debug)
fputc_readable (c, gdb_stdlog);
if (c == *p++)
{
if (*p == '\0')
{
immediate_quit--;
if (remote_debug)
fprintf_unfiltered (gdb_stdlog, "\": OK\n");
return 1;
}
}
else
{
p = string;
if (c == *p)
p++;
}
}
}
static int
mips_expect (const char *string)
{
return mips_expect_timeout (string, remote_timeout);
}
static int
mips_readchar (int timeout)
{
int ch;
static int state = 0;
int mips_monitor_prompt_len = strlen (mips_monitor_prompt);
{
int i;
i = timeout;
if (i == -1 && watchdog > 0)
i = watchdog;
}
if (state == mips_monitor_prompt_len)
timeout = 1;
ch = serial_readchar (mips_desc, timeout);
if (ch == SERIAL_TIMEOUT && timeout == -1)
{
target_mourn_inferior ();
error ("Watchdog has expired. Target detached.\n");
}
if (ch == SERIAL_EOF)
mips_error ("End of file from remote");
if (ch == SERIAL_ERROR)
mips_error ("Error reading from remote: %s", safe_strerror (errno));
if (remote_debug > 1)
{
if (ch != SERIAL_TIMEOUT)
fprintf_unfiltered (gdb_stdlog, "Read '%c' %d 0x%x\n", ch, ch, ch);
else
fprintf_unfiltered (gdb_stdlog, "Timed out in read\n");
}
if ((ch == SERIAL_TIMEOUT || ch == '@')
&& state == mips_monitor_prompt_len
&& !mips_initializing
&& !mips_exiting)
{
if (remote_debug > 0)
fprintf_unfiltered (gdb_stdlog, "Reinitializing MIPS debugging mode\n");
mips_need_reply = 0;
mips_initialize ();
state = 0;
error ("Remote board reset, debug protocol re-initialized.");
}
if (ch == mips_monitor_prompt[state])
++state;
else
state = 0;
return ch;
}
static int
mips_receive_header (unsigned char *hdr, int *pgarbage, int ch, int timeout)
{
int i;
while (1)
{
while (ch != SYN)
{
ch = mips_readchar (timeout);
if (ch == SERIAL_TIMEOUT)
return -1;
if (ch != SYN)
{
if (!mips_initializing || remote_debug > 0)
{
if (isprint (ch) || isspace (ch))
{
fputc_unfiltered (ch, gdb_stdtarg);
}
else
{
fputc_readable (ch, gdb_stdtarg);
}
gdb_flush (gdb_stdtarg);
}
if (! (isprint (ch) || isspace (ch)))
(*pgarbage) += 1;
if (mips_syn_garbage > 0
&& *pgarbage > mips_syn_garbage)
mips_error ("Debug protocol failure: more than %d characters before a sync.",
mips_syn_garbage);
}
}
for (i = 1; i < HDR_LENGTH; i++)
{
ch = mips_readchar (timeout);
if (ch == SERIAL_TIMEOUT)
return -1;
if (ch == SYN || !HDR_CHECK (ch))
break;
hdr[i] = ch;
}
if (i >= HDR_LENGTH)
return 0;
}
}
static int
mips_receive_trailer (unsigned char *trlr, int *pgarbage, int *pch, int timeout)
{
int i;
int ch;
for (i = 0; i < TRLR_LENGTH; i++)
{
ch = mips_readchar (timeout);
*pch = ch;
if (ch == SERIAL_TIMEOUT)
return -1;
if (!TRLR_CHECK (ch))
return -2;
trlr[i] = ch;
}
return 0;
}
static int
mips_cksum (const unsigned char *hdr, const unsigned char *data, int len)
{
const unsigned char *p;
int c;
int cksum;
cksum = 0;
c = HDR_LENGTH - 1;
p = hdr + 1;
while (c-- != 0)
cksum += *p++;
c = len;
p = data;
while (c-- != 0)
cksum += *p++;
return cksum;
}
static void
mips_send_packet (const char *s, int get_ack)
{
int len;
unsigned char *packet;
int cksum;
int try;
len = strlen (s);
if (len > DATA_MAXLEN)
mips_error ("MIPS protocol data packet too long: %s", s);
packet = (unsigned char *) alloca (HDR_LENGTH + len + TRLR_LENGTH + 1);
packet[HDR_INDX_SYN] = HDR_SET_SYN (1, len, mips_send_seq);
packet[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (1, len, mips_send_seq);
packet[HDR_INDX_LEN1] = HDR_SET_LEN1 (1, len, mips_send_seq);
packet[HDR_INDX_SEQ] = HDR_SET_SEQ (1, len, mips_send_seq);
memcpy (packet + HDR_LENGTH, s, len);
cksum = mips_cksum (packet, packet + HDR_LENGTH, len);
packet[HDR_LENGTH + len + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum);
packet[HDR_LENGTH + len + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
packet[HDR_LENGTH + len + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
mips_send_seq = (mips_send_seq + 1) % SEQ_MODULOS;
for (try = 0; try < mips_send_retries; try++)
{
int garbage;
int ch;
if (remote_debug > 0)
{
packet[HDR_LENGTH + len + TRLR_LENGTH] = '\0';
fprintf_unfiltered (gdb_stdlog, "Writing \"%s\"\n", packet + 1);
}
if (serial_write (mips_desc, packet,
HDR_LENGTH + len + TRLR_LENGTH) != 0)
mips_error ("write to target failed: %s", safe_strerror (errno));
if (!get_ack)
return;
garbage = 0;
ch = 0;
while (1)
{
unsigned char hdr[HDR_LENGTH + 1];
unsigned char trlr[TRLR_LENGTH + 1];
int err;
unsigned int seq;
err = mips_receive_header (hdr, &garbage, ch, mips_retransmit_wait);
if (err != 0)
break;
ch = 0;
if (HDR_IS_DATA (hdr))
{
int i;
len = HDR_GET_LEN (hdr);
for (i = 0; i < len; i++)
{
int rch;
rch = mips_readchar (remote_timeout);
if (rch == SYN)
{
ch = SYN;
break;
}
if (rch == SERIAL_TIMEOUT)
break;
}
if (i == len)
(void) mips_receive_trailer (trlr, &garbage, &ch,
remote_timeout);
continue;
}
if (HDR_GET_LEN (hdr) != 0)
continue;
err = mips_receive_trailer (trlr, &garbage, &ch,
mips_retransmit_wait);
if (err == -1)
break;
if (err != 0)
continue;
if (mips_cksum (hdr, (unsigned char *) NULL, 0)
!= TRLR_GET_CKSUM (trlr))
continue;
if (remote_debug > 0)
{
hdr[HDR_LENGTH] = '\0';
trlr[TRLR_LENGTH] = '\0';
fprintf_unfiltered (gdb_stdlog, "Got ack %d \"%s%s\"\n",
HDR_GET_SEQ (hdr), hdr + 1, trlr);
}
seq = HDR_GET_SEQ (hdr);
if (seq == mips_send_seq)
return;
if ((seq + 1) % SEQ_MODULOS == mips_send_seq)
break;
++garbage;
}
}
mips_error ("Remote did not acknowledge packet");
}
static int
mips_receive_packet (char *buff, int throw_error, int timeout)
{
int ch;
int garbage;
int len;
unsigned char ack[HDR_LENGTH + TRLR_LENGTH + 1];
int cksum;
ch = 0;
garbage = 0;
while (1)
{
unsigned char hdr[HDR_LENGTH];
unsigned char trlr[TRLR_LENGTH];
int i;
int err;
if (mips_receive_header (hdr, &garbage, ch, timeout) != 0)
{
if (throw_error)
mips_error ("Timed out waiting for remote packet");
else
return -1;
}
ch = 0;
if (!HDR_IS_DATA (hdr))
{
len = HDR_GET_LEN (hdr);
if (len == 0)
{
(void) mips_receive_trailer (trlr, &garbage, &ch, timeout);
}
if (remote_debug > 0)
fprintf_unfiltered (gdb_stdlog, "Ignoring unexpected ACK\n");
continue;
}
len = HDR_GET_LEN (hdr);
for (i = 0; i < len; i++)
{
int rch;
rch = mips_readchar (timeout);
if (rch == SYN)
{
ch = SYN;
break;
}
if (rch == SERIAL_TIMEOUT)
{
if (throw_error)
mips_error ("Timed out waiting for remote packet");
else
return -1;
}
buff[i] = rch;
}
if (i < len)
{
if (remote_debug > 0)
fprintf_unfiltered (gdb_stdlog,
"Got new SYN after %d chars (wanted %d)\n",
i, len);
continue;
}
err = mips_receive_trailer (trlr, &garbage, &ch, timeout);
if (err == -1)
{
if (throw_error)
mips_error ("Timed out waiting for packet");
else
return -1;
}
if (err == -2)
{
if (remote_debug > 0)
fprintf_unfiltered (gdb_stdlog, "Got SYN when wanted trailer\n");
continue;
}
if (HDR_GET_SEQ (hdr) != mips_receive_seq)
{
if (remote_debug > 0)
fprintf_unfiltered (gdb_stdlog,
"Ignoring sequence number %d (want %d)\n",
HDR_GET_SEQ (hdr), mips_receive_seq);
continue;
}
if (mips_cksum (hdr, buff, len) == TRLR_GET_CKSUM (trlr))
break;
if (remote_debug > 0)
printf_unfiltered ("Bad checksum; data %d, trailer %d\n",
mips_cksum (hdr, buff, len),
TRLR_GET_CKSUM (trlr));
ack[HDR_INDX_SYN] = HDR_SET_SYN (0, 0, mips_receive_seq);
ack[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (0, 0, mips_receive_seq);
ack[HDR_INDX_LEN1] = HDR_SET_LEN1 (0, 0, mips_receive_seq);
ack[HDR_INDX_SEQ] = HDR_SET_SEQ (0, 0, mips_receive_seq);
cksum = mips_cksum (ack, (unsigned char *) NULL, 0);
ack[HDR_LENGTH + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum);
ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
if (remote_debug > 0)
{
ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq,
ack + 1);
}
if (serial_write (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0)
{
if (throw_error)
mips_error ("write to target failed: %s", safe_strerror (errno));
else
return -1;
}
}
if (remote_debug > 0)
{
buff[len] = '\0';
printf_unfiltered ("Got packet \"%s\"\n", buff);
}
mips_receive_seq = (mips_receive_seq + 1) % SEQ_MODULOS;
ack[HDR_INDX_SYN] = HDR_SET_SYN (0, 0, mips_receive_seq);
ack[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (0, 0, mips_receive_seq);
ack[HDR_INDX_LEN1] = HDR_SET_LEN1 (0, 0, mips_receive_seq);
ack[HDR_INDX_SEQ] = HDR_SET_SEQ (0, 0, mips_receive_seq);
cksum = mips_cksum (ack, (unsigned char *) NULL, 0);
ack[HDR_LENGTH + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum);
ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
if (remote_debug > 0)
{
ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq,
ack + 1);
}
if (serial_write (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0)
{
if (throw_error)
mips_error ("write to target failed: %s", safe_strerror (errno));
else
return -1;
}
return len;
}
static ULONGEST
mips_request (int cmd,
ULONGEST addr,
ULONGEST data,
int *perr,
int timeout,
char *buff)
{
char myBuff[DATA_MAXLEN + 1];
int len;
int rpid;
char rcmd;
int rerrflg;
unsigned long rresponse;
if (buff == (char *) NULL)
buff = myBuff;
if (cmd != '\0')
{
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));
mips_send_packet (buff, 1);
mips_need_reply = 1;
}
if (perr == (int *) NULL)
return 0;
if (!mips_need_reply)
internal_error (__FILE__, __LINE__,
_("mips_request: Trying to get reply before command"));
mips_need_reply = 0;
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
|| (cmd != '\0' && rcmd != cmd))
mips_error ("Bad response from remote board");
if (rerrflg != 0)
{
*perr = 1;
errno = rresponse;
return 0;
}
*perr = 0;
return rresponse;
}
static void
mips_initialize_cleanups (void *arg)
{
mips_initializing = 0;
}
static void
mips_exit_cleanups (void *arg)
{
mips_exiting = 0;
}
static void
mips_send_command (const char *cmd, int prompt)
{
serial_write (mips_desc, cmd, strlen (cmd));
mips_expect (cmd);
mips_expect ("\n");
if (prompt)
mips_expect (mips_monitor_prompt);
}
static void
mips_enter_debug (void)
{
mips_send_seq = 0;
mips_receive_seq = 0;
if (mips_monitor != MON_IDT)
mips_send_command ("debug\r", 0);
else
mips_send_command ("db tty0\r", 0);
sleep (1);
serial_write (mips_desc, "\r", sizeof "\r" - 1);
if (mips_monitor != MON_IDT)
mips_expect ("\r");
{
char buff[DATA_MAXLEN + 1];
if (mips_receive_packet (buff, 1, 3) < 0)
mips_error ("Failed to initialize (didn't receive packet).");
}
}
static int
mips_exit_debug (void)
{
int err;
struct cleanup *old_cleanups = make_cleanup (mips_exit_cleanups, NULL);
mips_exiting = 1;
if (mips_monitor != MON_IDT)
{
mips_request ('x', 0, 0, NULL, mips_receive_wait, NULL);
mips_need_reply = 0;
if (!mips_expect (" break!"))
return -1;
}
else
mips_request ('x', 0, 0, &err, mips_receive_wait, NULL);
if (!mips_expect (mips_monitor_prompt))
return -1;
do_cleanups (old_cleanups);
return 0;
}
static void
mips_initialize (void)
{
int err;
struct cleanup *old_cleanups = make_cleanup (mips_initialize_cleanups, NULL);
int j;
if (mips_initializing)
{
warning ("internal error: mips_initialize called twice");
return;
}
mips_wait_flag = 0;
mips_initializing = 1;
if (mips_monitor != MON_IDT)
j = 0;
else
j = 1;
for (; j <= 4; j++)
{
switch (j)
{
case 0:
serial_flush_input (mips_desc);
serial_write (mips_desc, "\r", 1);
break;
case 1:
serial_send_break (mips_desc);
break;
case 2:
serial_write (mips_desc, "\003", 1);
break;
case 3:
{
if (mips_monitor != MON_IDT)
{
char tbuff[7];
serial_flush_output (mips_desc);
sprintf (tbuff, "\r/E/E\r");
serial_write (mips_desc, tbuff, 6);
}
else
{
char srec[10];
int i;
mips_make_srec (srec, '7', 0, NULL, 0);
for (i = 1; i <= 33; i++)
{
serial_write (mips_desc, srec, 8);
if (serial_readchar (mips_desc, 0) >= 0)
break;
}
}
}
break;
case 4:
mips_error ("Failed to initialize.");
}
if (mips_expect (mips_monitor_prompt))
break;
}
if (mips_monitor != MON_IDT)
{
mips_send_command ("\r", -1);
if (mips_monitor != MON_LSI)
mips_send_command ("set regsize 64\r", -1);
mips_send_command ("set hostport tty0\r", -1);
mips_send_command ("set brkcmd \"\"\r", -1);
mips_send_command ("db *\r", -1);
}
mips_enter_debug ();
if ((mips_monitor == MON_IDT
&& clear_breakpoint (-1, 0, BREAK_UNUSED) == 0)
|| mips_monitor == MON_LSI)
monitor_supports_breakpoints = 1;
else
monitor_supports_breakpoints = 0;
do_cleanups (old_cleanups);
mips_request ('r', 0, 0, &err, mips_receive_wait, NULL);
}
static void
common_open (struct target_ops *ops, char *name, int from_tty,
enum mips_monitor_type new_monitor,
const char *new_monitor_prompt)
{
char *ptype;
char *serial_port_name;
char *remote_name = 0;
char *local_name = 0;
char **argv;
if (name == 0)
error (
"To open a MIPS remote debugging connection, you need to specify what serial\n\
device is attached to the target board (e.g., /dev/ttya).\n"
"If you want to use TFTP to download to the board, specify the name of a\n"
"temporary file to be used by GDB for downloads as the second argument.\n"
"This filename must be in the form host:filename, where host is the name\n"
"of the host running the TFTP server, and the file must be readable by the\n"
"world. If the local name of the temporary file differs from the name as\n"
"seen from the board via TFTP, specify that name as the third parameter.\n");
if ((argv = buildargv (name)) == NULL)
nomem (0);
make_cleanup_freeargv (argv);
serial_port_name = xstrdup (argv[0]);
if (argv[1])
{
remote_name = argv[1];
if (argv[2])
local_name = argv[2];
}
target_preopen (from_tty);
if (mips_is_open)
unpush_target (current_ops);
mips_desc = serial_open (serial_port_name);
if (mips_desc == NULL)
perror_with_name (serial_port_name);
if (baud_rate != -1)
{
if (serial_setbaudrate (mips_desc, baud_rate))
{
serial_close (mips_desc);
perror_with_name (serial_port_name);
}
}
serial_raw (mips_desc);
if (remote_name)
{
if (strchr (remote_name, '#'))
{
udp_desc = serial_open (remote_name);
if (!udp_desc)
perror_with_name ("Unable to open UDP port");
udp_in_use = 1;
}
else
{
if (tftp_name)
xfree (tftp_name);
if (tftp_localname)
xfree (tftp_localname);
if (local_name == NULL)
if ((local_name = strchr (remote_name, ':')) != NULL)
local_name++;
if (local_name == NULL)
local_name = remote_name;
tftp_name = xstrdup (remote_name);
tftp_localname = xstrdup (local_name);
tftp_in_use = 1;
}
}
current_ops = ops;
mips_is_open = 1;
if (mips_monitor_prompt == NULL)
mips_monitor_prompt = xstrdup (new_monitor_prompt);
mips_monitor = new_monitor;
mips_initialize ();
if (from_tty)
printf_unfiltered ("Remote MIPS debugging using %s\n", serial_port_name);
push_target (ops);
deprecated_mips_set_processor_regs_hack ();
flush_cached_frames ();
registers_changed ();
stop_pc = read_pc ();
if (stop_pc != inlined_function_call_stack_pc ())
inlined_function_update_call_stack (stop_pc);
print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
clear_inlined_subroutine_print_frames ();
xfree (serial_port_name);
}
static void
mips_open (char *name, int from_tty)
{
const char *monitor_prompt = NULL;
if (TARGET_ARCHITECTURE != NULL
&& TARGET_ARCHITECTURE->arch == bfd_arch_mips)
{
switch (TARGET_ARCHITECTURE->mach)
{
case bfd_mach_mips4100:
case bfd_mach_mips4300:
case bfd_mach_mips4600:
case bfd_mach_mips4650:
case bfd_mach_mips5000:
monitor_prompt = "<RISQ> ";
break;
}
}
if (monitor_prompt == NULL)
monitor_prompt = "<IDT>";
common_open (&mips_ops, name, from_tty, MON_IDT, monitor_prompt);
}
static void
pmon_open (char *name, int from_tty)
{
common_open (&pmon_ops, name, from_tty, MON_PMON, "PMON> ");
}
static void
ddb_open (char *name, int from_tty)
{
common_open (&ddb_ops, name, from_tty, MON_DDB, "NEC010>");
}
static void
lsi_open (char *name, int from_tty)
{
int i;
for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
lsi_breakpoints[i].type = BREAK_UNUSED;
common_open (&lsi_ops, name, from_tty, MON_LSI, "PMON> ");
}
static void
mips_close (int quitting)
{
if (mips_is_open)
{
(void) mips_exit_debug ();
close_ports ();
}
}
static void
mips_detach (char *args, int from_tty)
{
if (args)
error ("Argument given to \"detach\" when remotely debugging.");
pop_target ();
mips_close (1);
if (from_tty)
printf_unfiltered ("Ending remote MIPS debugging.\n");
}
static void
mips_resume (ptid_t ptid, int step, enum target_signal siggnal)
{
int err;
mips_request (step ? 's' : 'c', 1, siggnal,
mips_monitor == MON_LSI && step ? &err : (int *) NULL,
mips_receive_wait, NULL);
}
static enum target_signal
mips_signal_from_protocol (int sig)
{
if (sig <= 0
|| sig > 31)
return TARGET_SIGNAL_UNKNOWN;
return (enum target_signal) sig;
}
static ptid_t
mips_wait (ptid_t ptid, struct target_waitstatus *status)
{
int rstatus;
int err;
char buff[DATA_MAXLEN];
int rpc, rfp, rsp;
char flags[20];
int nfields;
int i;
interrupt_count = 0;
hit_watchpoint = 0;
if (!mips_need_reply)
{
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
return inferior_ptid;
}
mips_wait_flag = 1;
rstatus = mips_request ('\000', 0, 0, &err, -1, buff);
mips_wait_flag = 0;
if (err)
mips_error ("Remote failure: %s", safe_strerror (errno));
if (mips_monitor == MON_PMON)
{
mips_exit_debug ();
mips_enter_debug ();
}
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)
{
char buf[MAX_REGISTER_SIZE];
store_unsigned_integer (buf, register_size (current_gdbarch, PC_REGNUM), rpc);
regcache_raw_supply (current_regcache, PC_REGNUM, buf);
store_unsigned_integer (buf, register_size (current_gdbarch, PC_REGNUM), rfp);
regcache_raw_supply (current_regcache, 30, buf);
store_unsigned_integer (buf, register_size (current_gdbarch, SP_REGNUM), rsp);
regcache_raw_supply (current_regcache, SP_REGNUM, buf);
store_unsigned_integer (buf, register_size (current_gdbarch, DEPRECATED_FP_REGNUM), 0);
regcache_raw_supply (current_regcache, DEPRECATED_FP_REGNUM, buf);
if (nfields == 9)
{
int i;
for (i = 0; i <= 2; i++)
if (flags[i] == 'r' || flags[i] == 'w')
hit_watchpoint = 1;
else if (flags[i] == '\000')
break;
}
}
if (strcmp (target_shortname, "lsi") == 0)
{
#if 0
int i;
CORE_ADDR pc = read_pc ();
hit_watchpoint = 1;
for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
{
if (lsi_breakpoints[i].addr == pc
&& lsi_breakpoints[i].type == BREAK_FETCH)
{
hit_watchpoint = 0;
break;
}
}
#else
if (nfields == 1 && rpc == 1)
hit_watchpoint = 1;
#endif
}
if ((rstatus & 0xff) == 0)
{
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = (((rstatus) >> 8) & 0xff);
}
else if ((rstatus & 0xff) == 0x7f)
{
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = mips_signal_from_protocol (((rstatus) >> 8) & 0xff);
if (strcmp (target_shortname, "lsi") == 0)
{
char *func_name;
CORE_ADDR func_start;
CORE_ADDR pc = read_pc ();
find_pc_partial_function_no_inlined (pc, &func_name, &func_start,
NULL);
if (func_name != NULL && strcmp (func_name, "_exit") == 0
&& func_start == pc)
status->kind = TARGET_WAITKIND_EXITED;
}
}
else
{
status->kind = TARGET_WAITKIND_SIGNALLED;
status->value.sig = mips_signal_from_protocol (rstatus & 0x7f);
}
return inferior_ptid;
}
#define REGNO_OFFSET 96
static int
mips_map_regno (int regno)
{
if (regno < 32)
return regno;
if (regno >= mips_regnum (current_gdbarch)->fp0
&& regno < mips_regnum (current_gdbarch)->fp0 + 32)
return regno - mips_regnum (current_gdbarch)->fp0 + 32;
else if (regno == mips_regnum (current_gdbarch)->pc)
return REGNO_OFFSET + 0;
else if (regno == mips_regnum (current_gdbarch)->cause)
return REGNO_OFFSET + 1;
else if (regno == mips_regnum (current_gdbarch)->hi)
return REGNO_OFFSET + 2;
else if (regno == mips_regnum (current_gdbarch)->lo)
return REGNO_OFFSET + 3;
else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
return REGNO_OFFSET + 4;
else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
return REGNO_OFFSET + 5;
else
return 0;
}
static void
mips_fetch_registers (int regno)
{
unsigned LONGEST val;
int err;
if (regno == -1)
{
for (regno = 0; regno < NUM_REGS; regno++)
mips_fetch_registers (regno);
return;
}
if (regno == DEPRECATED_FP_REGNUM || regno == MIPS_ZERO_REGNUM)
val = 0;
else
{
int pmon_reg = mips_map_regno (regno);
if (regno != 0 && pmon_reg == 0)
val = 0;
else
{
if (mips_monitor == MON_DDB)
val = (unsigned) mips_request ('t', pmon_reg, 0,
&err, mips_receive_wait, NULL);
else
val = mips_request ('r', pmon_reg, 0,
&err, mips_receive_wait, NULL);
if (err)
mips_error ("Can't read register %d: %s", regno,
safe_strerror (errno));
}
}
{
char buf[MAX_REGISTER_SIZE];
store_unsigned_integer (buf, register_size (current_gdbarch, regno), val);
regcache_raw_supply (current_regcache, regno, buf);
}
}
static void
mips_prepare_to_store (void)
{
}
static void
mips_store_registers (int regno)
{
int err;
if (regno == -1)
{
for (regno = 0; regno < NUM_REGS; regno++)
mips_store_registers (regno);
return;
}
mips_request ('R', mips_map_regno (regno),
read_register (regno),
&err, mips_receive_wait, NULL);
if (err)
mips_error ("Can't write register %d: %s", regno, safe_strerror (errno));
}
static unsigned int
mips_fetch_word (CORE_ADDR addr)
{
unsigned int val;
int err;
val = mips_request ('d', addr, 0, &err, mips_receive_wait, NULL);
if (err)
{
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));
}
return val;
}
static int
mips_store_word (CORE_ADDR addr, unsigned int val, char *old_contents)
{
int err;
unsigned int oldcontents;
oldcontents = mips_request ('D', addr, val, &err,
mips_receive_wait, NULL);
if (err)
{
oldcontents = mips_request ('I', addr, val, &err,
mips_receive_wait, NULL);
if (err)
return errno;
}
if (old_contents != NULL)
store_unsigned_integer (old_contents, 4, oldcontents);
return 0;
}
static int mask_address_p = 1;
static int
mips_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
struct mem_attrib *attrib, struct target_ops *target)
{
int i;
CORE_ADDR addr;
int count;
char *buffer;
int status;
if (mask_address_p)
memaddr &= (CORE_ADDR) 0xffffffff;
addr = memaddr & ~3;
count = (((memaddr + len) - addr) + 3) / 4;
buffer = alloca (count * 4);
if (write)
{
if (addr != memaddr || len < 4)
{
store_unsigned_integer (&buffer[0], 4, mips_fetch_word (addr));
}
if (count > 1)
{
store_unsigned_integer (&buffer[(count - 1) * 4], 4,
mips_fetch_word (addr + (count - 1) * 4));
}
memcpy ((char *) buffer + (memaddr & 3), myaddr, len);
for (i = 0; i < count; i++, addr += 4)
{
status = mips_store_word (addr,
extract_unsigned_integer (&buffer[i * 4], 4),
NULL);
if (i % 256 == 255)
{
printf_unfiltered ("*");
gdb_flush (gdb_stdout);
}
if (status)
{
errno = status;
return 0;
}
}
if (count >= 256)
printf_unfiltered ("\n");
}
else
{
for (i = 0; i < count; i++, addr += 4)
{
store_unsigned_integer (&buffer[i * 4], 4, mips_fetch_word (addr));
QUIT;
}
memcpy (myaddr, buffer + (memaddr & 3), len);
}
return len;
}
static void
mips_files_info (struct target_ops *ignore)
{
printf_unfiltered ("Debugging a MIPS board over a serial line.\n");
}
static void
mips_kill (void)
{
if (!mips_wait_flag)
return;
interrupt_count++;
if (interrupt_count >= 2)
{
interrupt_count = 0;
target_terminal_ours ();
if (query ("Interrupted while waiting for the program.\n\
Give up (and stop debugging it)? "))
{
mips_wait_flag = 0;
close_ports ();
printf_unfiltered ("Ending remote MIPS debugging.\n");
target_mourn_inferior ();
deprecated_throw_reason (RETURN_QUIT);
}
target_terminal_inferior ();
}
if (remote_debug > 0)
printf_unfiltered ("Sending break\n");
serial_send_break (mips_desc);
#if 0
if (mips_is_open)
{
char cc;
cc = '\003';
serial_write (mips_desc, &cc, 1);
sleep (1);
target_mourn_inferior ();
}
#endif
}
static void
mips_create_inferior (char *execfile, char *args, char **env, int from_tty)
{
CORE_ADDR entry_pt;
if (args && *args)
{
warning ("\
Can't pass arguments to remote MIPS board; arguments ignored.");
execute_command ("set args", 0);
}
if (execfile == 0 || exec_bfd == 0)
error ("No executable file specified");
entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
init_wait_for_inferior ();
proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
}
static void
mips_mourn_inferior (void)
{
if (current_ops != NULL)
unpush_target (current_ops);
generic_mourn_inferior ();
}
static int
mips_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
{
if (monitor_supports_breakpoints)
return set_breakpoint (addr, MIPS_INSN32_SIZE, BREAK_FETCH);
else
return memory_insert_breakpoint (addr, contents_cache);
}
static int
mips_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
{
if (monitor_supports_breakpoints)
return clear_breakpoint (addr, MIPS_INSN32_SIZE, BREAK_FETCH);
else
return memory_remove_breakpoint (addr, contents_cache);
}
int
mips_can_use_watchpoint (int type, int cnt, int othertype)
{
return cnt < MAX_LSI_BREAKPOINTS && strcmp (target_shortname, "lsi") == 0;
}
static unsigned long
calculate_mask (CORE_ADDR addr, int len)
{
unsigned long mask;
int i;
mask = addr ^ (addr + len - 1);
for (i = 32; i >= 0; i--)
if (mask == 0)
break;
else
mask >>= 1;
mask = (unsigned long) 0xffffffff >> i;
return mask;
}
int
mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
{
if (set_breakpoint (addr, len, type))
return -1;
return 0;
}
int
mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
{
if (clear_breakpoint (addr, len, type))
return -1;
return 0;
}
int
mips_stopped_by_watchpoint (void)
{
return hit_watchpoint;
}
static int
set_breakpoint (CORE_ADDR addr, int len, enum break_type type)
{
return common_breakpoint (1, addr, len, type);
}
static int
clear_breakpoint (CORE_ADDR addr, int len, enum break_type type)
{
return common_breakpoint (0, addr, len, type);
}
static int
check_lsi_error (CORE_ADDR addr, int rerrflg)
{
struct lsi_error *err;
char *saddr = paddr_nz (addr);
if (rerrflg == 0)
return 0;
if (rerrflg & W_WARN)
{
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,
"common_breakpoint (0x%s): Warning: %s\n",
saddr,
err->string);
}
}
if (!found)
fprintf_unfiltered (gdb_stderr,
"common_breakpoint (0x%s): Unknown warning: 0x%x\n",
saddr,
rerrflg);
}
return 0;
}
for (err = lsi_error_table; err->code != 0; err++)
{
if ((err->code & rerrflg) == err->code)
{
fprintf_unfiltered (gdb_stderr,
"common_breakpoint (0x%s): Error: %s\n",
saddr,
err->string);
return 1;
}
}
fprintf_unfiltered (gdb_stderr,
"common_breakpoint (0x%s): Unknown error: 0x%x\n",
saddr,
rerrflg);
return 1;
}
static int
common_breakpoint (int set, CORE_ADDR addr, int len, enum break_type type)
{
char buf[DATA_MAXLEN + 1];
char cmd, rcmd;
int rpid, rerrflg, rresponse, rlen;
int nfields;
addr = ADDR_BITS_REMOVE (addr);
if (mips_monitor == MON_LSI)
{
if (set == 0)
{
int i;
for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
if (lsi_breakpoints[i].type == type
&& lsi_breakpoints[i].addr == addr
&& lsi_breakpoints[i].len == len)
break;
if (i == MAX_LSI_BREAKPOINTS)
{
warning ("common_breakpoint: Attempt to clear bogus breakpoint at %s\n",
paddr_nz (addr));
return 1;
}
lsi_breakpoints[i].type = BREAK_UNUSED;
sprintf (buf, "0x0 b 0x%x 0x0", i);
mips_send_packet (buf, 1);
rlen = mips_receive_packet (buf, 1, mips_receive_wait);
buf[rlen] = '\0';
nfields = sscanf (buf, "0x%x b 0x0 0x%x", &rpid, &rerrflg);
if (nfields != 2)
mips_error ("common_breakpoint: Bad response from remote board: %s", buf);
return (check_lsi_error (addr, rerrflg));
}
else
{
if (type == BREAK_FETCH)
{
cmd = 'B';
sprintf (buf, "0x0 B 0x%s 0x0", paddr_nz (addr));
}
else
{
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));
}
mips_send_packet (buf, 1);
rlen = mips_receive_packet (buf, 1, mips_receive_wait);
buf[rlen] = '\0';
nfields = sscanf (buf, "0x%x %c 0x%x 0x%x",
&rpid, &rcmd, &rresponse, &rerrflg);
if (nfields != 4 || rcmd != cmd || rresponse > 255)
mips_error ("common_breakpoint: Bad response from remote board: %s", buf);
if (rerrflg != 0)
if (check_lsi_error (addr, rerrflg))
return 1;
lsi_breakpoints[rresponse].type = type;
lsi_breakpoints[rresponse].addr = addr;
lsi_breakpoints[rresponse].len = len;
return 0;
}
}
else
{
unsigned long mask;
mask = calculate_mask (addr, len);
addr &= ~mask;
if (set)
{
char *flags;
switch (type)
{
case BREAK_WRITE:
flags = "w";
break;
case BREAK_READ:
flags = "r";
break;
case BREAK_ACCESS:
flags = "rw";
break;
case BREAK_FETCH:
flags = "f";
break;
default:
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
}
cmd = 'B';
sprintf (buf, "0x0 B 0x%s 0x%s %s", paddr_nz (addr),
paddr_nz (mask), flags);
}
else
{
cmd = 'b';
sprintf (buf, "0x0 b 0x%s", paddr_nz (addr));
}
mips_send_packet (buf, 1);
rlen = mips_receive_packet (buf, 1, mips_receive_wait);
buf[rlen] = '\0';
nfields = sscanf (buf, "0x%x %c 0x%x 0x%x",
&rpid, &rcmd, &rerrflg, &rresponse);
if (nfields != 4 || rcmd != cmd)
mips_error ("common_breakpoint: Bad response from remote board: %s",
buf);
if (rerrflg != 0)
{
if (mips_monitor == MON_DDB)
rresponse = rerrflg;
if (rresponse != 22)
fprintf_unfiltered (gdb_stderr,
"common_breakpoint (0x%s): Got error: 0x%x\n",
paddr_nz (addr), rresponse);
return 1;
}
}
return 0;
}
static void
send_srec (char *srec, int len, CORE_ADDR addr)
{
while (1)
{
int ch;
serial_write (mips_desc, srec, len);
ch = mips_readchar (remote_timeout);
switch (ch)
{
case SERIAL_TIMEOUT:
error ("Timeout during download.");
break;
case 0x6:
return;
case 0x15:
fprintf_unfiltered (gdb_stderr, "Download got a NACK at byte %s! Retrying.\n", paddr_u (addr));
continue;
default:
error ("Download got unexpected ack char: 0x%x, retrying.\n", ch);
}
}
}
static void
mips_load_srec (char *args)
{
bfd *abfd;
asection *s;
char *buffer, srec[1024];
unsigned int i;
unsigned int srec_frame = 200;
int reclen;
static int hashmark = 1;
buffer = alloca (srec_frame * 2 + 256);
abfd = bfd_openr (args, 0);
if (!abfd)
{
printf_filtered ("Unable to open file %s\n", args);
return;
}
if (bfd_check_format (abfd, bfd_object) == 0)
{
printf_filtered ("File is not an object file\n");
return;
}
mips_send_command (LOAD_CMD, 0);
for (s = abfd->sections; s; s = s->next)
{
if (s->flags & SEC_LOAD)
{
unsigned int numbytes;
printf_filtered ("%s\t: 0x%4lx .. 0x%4lx ", s->name,
(long) s->vma,
(long) (s->vma + bfd_get_section_size (s)));
gdb_flush (gdb_stdout);
for (i = 0; i < bfd_get_section_size (s); i += numbytes)
{
numbytes = min (srec_frame, bfd_get_section_size (s) - i);
bfd_get_section_contents (abfd, s, buffer, i, numbytes);
reclen = mips_make_srec (srec, '3', s->vma + i,
buffer, numbytes);
send_srec (srec, reclen, s->vma + i);
if (deprecated_ui_load_progress_hook)
deprecated_ui_load_progress_hook (s->name, i);
if (hashmark)
{
putchar_unfiltered ('#');
gdb_flush (gdb_stdout);
}
}
putchar_unfiltered ('\n');
}
}
if (hashmark)
putchar_unfiltered ('\n');
reclen = mips_make_srec (srec, '7', abfd->start_address, NULL, 0);
send_srec (srec, reclen, abfd->start_address);
serial_flush_input (mips_desc);
}
static int
mips_make_srec (char *buf, int type, CORE_ADDR memaddr, unsigned char *myaddr,
int len)
{
unsigned char checksum;
int i;
buf[0] = 'S';
buf[1] = type;
buf[2] = len + 4 + 1;
buf[3] = memaddr >> 24;
buf[4] = memaddr >> 16;
buf[5] = memaddr >> 8;
buf[6] = memaddr;
memcpy (&buf[7], myaddr, len);
checksum = 0;
buf += 2;
for (i = 0; i < len + 4 + 1; i++)
checksum += *buf++;
*buf = ~checksum;
return len + 8;
}
#define DOETXACK (1)
static char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,.";
static int
pmon_makeb64 (unsigned long v, char *p, int n, int *chksum)
{
int count = (n / 6);
if ((n % 12) != 0)
{
fprintf_unfiltered (gdb_stderr,
"Fast encoding bitcount must be a multiple of 12bits: %dbit%s\n", n, (n == 1) ? "" : "s");
return (0);
}
if (n > 36)
{
fprintf_unfiltered (gdb_stderr,
"Fast encoding cannot process more than 36bits at the moment: %dbits\n", n);
return (0);
}
if (chksum != NULL)
{
switch (n)
{
case 36:
*chksum += ((v >> 24) & 0xFFF);
case 24:
*chksum += ((v >> 12) & 0xFFF);
case 12:
*chksum += ((v >> 0) & 0xFFF);
}
}
do
{
n -= 6;
*p++ = encoding[(v >> n) & 0x3F];
}
while (n > 0);
return (count);
}
static int
pmon_zeroset (int recsize, char **buff, int *amount, unsigned int *chksum)
{
int count;
sprintf (*buff, "/Z");
count = pmon_makeb64 (*amount, (*buff + 2), 12, chksum);
*buff += (count + 2);
*amount = 0;
return (recsize + count + 2);
}
static int
pmon_checkset (int recsize, char **buff, int *value)
{
int count;
sprintf (*buff, "/C");
count = pmon_makeb64 (*value, (*buff + 2), 12, NULL);
*buff += (count + 2);
sprintf (*buff, "\n");
*buff += 2;
*value = 0;
return (recsize + count + 3);
}
#define CHECKSIZE (4 + 4 + 4 + 2)
#define BINCHUNK (1024)
#define MAXRECSIZE (550)
static void
pmon_make_fastrec (char **outbuf, unsigned char *inbuf, int *inptr,
int inamount, int *recsize, unsigned int *csum,
unsigned int *zerofill)
{
int count = 0;
char *p = *outbuf;
while ((*recsize < (MAXRECSIZE - CHECKSIZE)) && ((inamount - *inptr) > 0))
{
if ((inamount - *inptr) < 3)
{
if (*zerofill != 0)
*recsize = pmon_zeroset (*recsize, &p, zerofill, csum);
sprintf (p, "/B");
count = pmon_makeb64 (inbuf[*inptr], &p[2], 12, csum);
p += (2 + count);
*recsize += (2 + count);
(*inptr)++;
}
else
{
unsigned int value = ((inbuf[*inptr + 0] << 16) | (inbuf[*inptr + 1] << 8) | inbuf[*inptr + 2]);
if (value == 0x00000000)
{
(*zerofill)++;
if (*zerofill == 0xFFF)
*recsize = pmon_zeroset (*recsize, &p, zerofill, csum);
}
else
{
if (*zerofill != 0)
*recsize = pmon_zeroset (*recsize, &p, zerofill, csum);
count = pmon_makeb64 (value, p, 24, csum);
p += count;
*recsize += count;
}
*inptr += 3;
}
}
*outbuf = p;
return;
}
static int
pmon_check_ack (char *mesg)
{
#if defined(DOETXACK)
int c;
if (!tftp_in_use)
{
c = serial_readchar (udp_in_use ? udp_desc : mips_desc,
remote_timeout);
if ((c == SERIAL_TIMEOUT) || (c != 0x06))
{
fprintf_unfiltered (gdb_stderr,
"Failed to receive valid ACK for %s\n", mesg);
return (-1);
}
}
#endif
return (0);
}
static void
pmon_start_download (void)
{
if (tftp_in_use)
{
if ((tftp_file = fopen (tftp_localname, "w")) == NULL)
perror_with_name (tftp_localname);
}
else
{
mips_send_command (udp_in_use ? LOAD_CMD_UDP : LOAD_CMD, 0);
mips_expect ("Downloading from ");
mips_expect (udp_in_use ? "udp" : "tty0");
mips_expect (", ^C to abort\r\n");
}
}
static int
mips_expect_download (char *string)
{
if (!mips_expect (string))
{
fprintf_unfiltered (gdb_stderr, "Load did not complete successfully.\n");
if (tftp_in_use)
remove (tftp_localname);
return 0;
}
else
return 1;
}
static void
pmon_check_entry_address (char *entry_address, int final)
{
char hexnumber[9];
mips_expect_timeout (entry_address, tftp_in_use ? 15 : remote_timeout);
sprintf (hexnumber, "%x", final);
mips_expect (hexnumber);
mips_expect ("\r\n");
}
static int
pmon_check_total (int bintotal)
{
char hexnumber[9];
mips_expect ("\r\ntotal = 0x");
sprintf (hexnumber, "%x", bintotal);
mips_expect (hexnumber);
return mips_expect_download (" bytes\r\n");
}
static void
pmon_end_download (int final, int bintotal)
{
char hexnumber[9];
if (tftp_in_use)
{
static char *load_cmd_prefix = "load -b -s ";
char *cmd;
struct stat stbuf;
fclose (tftp_file);
tftp_file = NULL;
if (stat (tftp_localname, &stbuf) == 0)
chmod (tftp_localname, stbuf.st_mode | S_IROTH);
mips_send_command ("initEther\r", -1);
cmd = xmalloc (strlen (load_cmd_prefix) + strlen (tftp_name) + 2);
strcpy (cmd, load_cmd_prefix);
strcat (cmd, tftp_name);
strcat (cmd, "\r");
mips_send_command (cmd, 0);
xfree (cmd);
if (!mips_expect_download ("Downloading from "))
return;
if (!mips_expect_download (tftp_name))
return;
if (!mips_expect_download (", ^C to abort\r\n"))
return;
}
switch (mips_monitor)
{
case MON_LSI:
pmon_check_ack ("termination");
pmon_check_entry_address ("Entry address is ", final);
if (!pmon_check_total (bintotal))
return;
break;
default:
pmon_check_entry_address ("Entry Address = ", final);
pmon_check_ack ("termination");
if (!pmon_check_total (bintotal))
return;
break;
}
if (tftp_in_use)
remove (tftp_localname);
}
static void
pmon_download (char *buffer, int length)
{
if (tftp_in_use)
fwrite (buffer, 1, length, tftp_file);
else
serial_write (udp_in_use ? udp_desc : mips_desc, buffer, length);
}
static void
pmon_load_fast (char *file)
{
bfd *abfd;
asection *s;
unsigned char *binbuf;
char *buffer;
int reclen;
unsigned int csum = 0;
int hashmark = !tftp_in_use;
int bintotal = 0;
int final = 0;
int finished = 0;
buffer = (char *) xmalloc (MAXRECSIZE + 1);
binbuf = (unsigned char *) xmalloc (BINCHUNK);
abfd = bfd_openr (file, 0);
if (!abfd)
{
printf_filtered ("Unable to open file %s\n", file);
return;
}
if (bfd_check_format (abfd, bfd_object) == 0)
{
printf_filtered ("File is not an object file\n");
return;
}
mips_send_command ("set dlproto etxack\r", -1);
mips_send_command ("set dlecho off\r", -1);
pmon_start_download ();
sprintf (buffer, "/Kxx\n");
reclen = strlen (buffer);
pmon_download (buffer, reclen);
finished = pmon_check_ack ("/Kxx");
for (s = abfd->sections; s && !finished; s = s->next)
if (s->flags & SEC_LOAD)
{
bintotal += bfd_get_section_size (s);
final = (s->vma + bfd_get_section_size (s));
printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, (unsigned int) s->vma,
(unsigned int) (s->vma + bfd_get_section_size (s)));
gdb_flush (gdb_stdout);
sprintf (buffer, "/A");
reclen = pmon_makeb64 (s->vma, &buffer[2], 36, &csum);
buffer[2 + reclen] = '\n';
buffer[3 + reclen] = '\0';
reclen += 3;
pmon_download (buffer, reclen);
finished = pmon_check_ack ("/A");
if (!finished)
{
unsigned int binamount;
unsigned int zerofill = 0;
char *bp = buffer;
unsigned int i;
reclen = 0;
for (i = 0;
i < bfd_get_section_size (s) && !finished;
i += binamount)
{
int binptr = 0;
binamount = min (BINCHUNK, bfd_get_section_size (s) - i);
bfd_get_section_contents (abfd, s, binbuf, i, binamount);
for (; ((binamount - binptr) > 0);)
{
pmon_make_fastrec (&bp, binbuf, &binptr, binamount,
&reclen, &csum, &zerofill);
if (reclen >= (MAXRECSIZE - CHECKSIZE))
{
reclen = pmon_checkset (reclen, &bp, &csum);
pmon_download (buffer, reclen);
finished = pmon_check_ack ("data record");
if (finished)
{
zerofill = 0;
break;
}
if (deprecated_ui_load_progress_hook)
deprecated_ui_load_progress_hook (s->name, i);
if (hashmark)
{
putchar_unfiltered ('#');
gdb_flush (gdb_stdout);
}
bp = buffer;
reclen = 0;
}
}
}
if (zerofill != 0)
reclen = pmon_zeroset (reclen, &bp, &zerofill, &csum);
if (reclen > 0)
{
reclen = pmon_checkset (reclen, &bp, &csum);
pmon_download (buffer, reclen);
finished = pmon_check_ack ("record remnant");
}
}
putchar_unfiltered ('\n');
}
sprintf (buffer, "/E/E\n");
reclen = strlen (buffer);
pmon_download (buffer, reclen);
if (finished)
{
serial_flush_input (udp_in_use ? udp_desc : mips_desc);
}
else
{
pmon_end_download (final, bintotal);
}
return;
}
static void
mips_load (char *file, int from_tty)
{
if (mips_exit_debug ())
error ("mips_load: Couldn't get into monitor mode.");
if (mips_monitor != MON_IDT)
pmon_load_fast (file);
else
mips_load_srec (file);
mips_initialize ();
if (mips_monitor != MON_IDT)
{
deprecated_register_valid[PC_REGNUM] = 0;
}
if (exec_bfd)
write_pc (bfd_get_start_address (exec_bfd));
inferior_ptid = null_ptid;
clear_symtab_users ();
}
static void
pmon_command (char *args, int from_tty)
{
char buf[DATA_MAXLEN + 1];
int rlen;
sprintf (buf, "0x0 %s", args);
mips_send_packet (buf, 1);
printf_filtered ("Send packet: %s\n", buf);
rlen = mips_receive_packet (buf, 1, mips_receive_wait);
buf[rlen] = '\0';
printf_filtered ("Received packet: %s\n", buf);
}
extern initialize_file_ftype _initialize_remote_mips;
void
_initialize_remote_mips (void)
{
mips_ops.to_longname = "Remote MIPS debugging over serial line";
mips_ops.to_close = mips_close;
mips_ops.to_detach = mips_detach;
mips_ops.to_resume = mips_resume;
mips_ops.to_fetch_registers = mips_fetch_registers;
mips_ops.to_store_registers = mips_store_registers;
mips_ops.to_prepare_to_store = mips_prepare_to_store;
mips_ops.deprecated_xfer_memory = mips_xfer_memory;
mips_ops.to_files_info = mips_files_info;
mips_ops.to_insert_breakpoint = mips_insert_breakpoint;
mips_ops.to_remove_breakpoint = mips_remove_breakpoint;
mips_ops.to_insert_watchpoint = mips_insert_watchpoint;
mips_ops.to_remove_watchpoint = mips_remove_watchpoint;
mips_ops.to_stopped_by_watchpoint = mips_stopped_by_watchpoint;
mips_ops.to_can_use_hw_breakpoint = mips_can_use_watchpoint;
mips_ops.to_kill = mips_kill;
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_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_magic = OPS_MAGIC;
pmon_ops = ddb_ops = lsi_ops = mips_ops;
mips_ops.to_shortname = "mips";
mips_ops.to_doc = "\
Debug a board using the MIPS remote debugging protocol over a serial line.\n\
The argument is the device it is connected to or, if it contains a colon,\n\
HOST:PORT to access a board over a network";
mips_ops.to_open = mips_open;
mips_ops.to_wait = mips_wait;
pmon_ops.to_shortname = "pmon";
pmon_ops.to_doc = "\
Debug a board using the PMON MIPS remote debugging protocol over a serial\n\
line. The argument is the device it is connected to or, if it contains a\n\
colon, HOST:PORT to access a board over a network";
pmon_ops.to_open = pmon_open;
pmon_ops.to_wait = mips_wait;
ddb_ops.to_shortname = "ddb";
ddb_ops.to_doc = "\
Debug a board using the PMON MIPS remote debugging protocol over a serial\n\
line. The first argument is the device it is connected to or, if it contains\n\
a colon, HOST:PORT to access a board over a network. The optional second\n\
parameter is the temporary file in the form HOST:FILENAME to be used for\n\
TFTP downloads to the board. The optional third parameter is the local name\n\
of the TFTP temporary file, if it differs from the filename seen by the board.";
ddb_ops.to_open = ddb_open;
ddb_ops.to_wait = mips_wait;
lsi_ops.to_shortname = "lsi";
lsi_ops.to_doc = pmon_ops.to_doc;
lsi_ops.to_open = lsi_open;
lsi_ops.to_wait = mips_wait;
add_target (&mips_ops);
add_target (&pmon_ops);
add_target (&ddb_ops);
add_target (&lsi_ops);
add_setshow_zinteger_cmd ("timeout", no_class, &mips_receive_wait, _("\
Set timeout in seconds for remote MIPS serial I/O."), _("\
Show timeout in seconds for remote MIPS serial I/O."), NULL,
NULL,
NULL,
&setlist, &showlist);
add_setshow_zinteger_cmd ("retransmit-timeout", no_class,
&mips_retransmit_wait, _("\
Set retransmit timeout in seconds for remote MIPS serial I/O."), _("\
Show retransmit timeout in seconds for remote MIPS serial I/O."), _("\
This is the number of seconds to wait for an acknowledgement to a packet\n\
before resending the packet."),
NULL,
NULL,
&setlist, &showlist);
add_setshow_zinteger_cmd ("syn-garbage-limit", no_class,
&mips_syn_garbage, _("\
Set the maximum number of characters to ignore when scanning for a SYN."), _("\
Show the maximum number of characters to ignore when scanning for a SYN."), _("\
This is the maximum number of characters GDB will ignore when trying to\n\
synchronize with the remote system. A value of -1 means that there is no\n\
limit. (Note that these characters are printed out even though they are\n\
ignored.)"),
NULL,
NULL,
&setlist, &showlist);
add_setshow_string_cmd ("monitor-prompt", class_obscure,
&mips_monitor_prompt, _("\
Set the prompt that GDB expects from the monitor."), _("\
Show the prompt that GDB expects from the monitor."), NULL,
NULL,
NULL,
&setlist, &showlist);
add_setshow_zinteger_cmd ("monitor-warnings", class_obscure,
&monitor_warnings, _("\
Set printing of monitor warnings."), _("\
Show printing of monitor warnings."), _("\
When enabled, monitor warnings about hardware breakpoints will be displayed."),
NULL,
NULL,
&setlist, &showlist);
add_com ("pmon", class_obscure, pmon_command,
_("Send a packet to PMON (must be in debug mode)."));
add_setshow_boolean_cmd ("mask-address", no_class, &mask_address_p, _("\
Set zeroing of upper 32 bits of 64-bit addresses when talking to PMON targets."), _("\
Show zeroing of upper 32 bits of 64-bit addresses when talking to PMON targets."), _("\
Use \"on\" to enable the masking and \"off\" to disable it."),
NULL,
NULL,
&setlist, &showlist);
}