#include "defs.h"
#include "inferior.h"
#include "gdb_wait.h"
#include "value.h"
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include "gdb_string.h"
#include "terminal.h"
#include "minimon.h"
#include "target.h"
#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
#define DRAIN_INPUT() (msg_recv_serial((union msg_t*)0))
extern int stop_soon_quietly;
static void mm_resume ();
static void mm_fetch_registers ();
static int fetch_register ();
static void mm_store_registers ();
static int store_register ();
static int regnum_to_srnum ();
static void mm_close ();
static char *msg_str ();
static char *error_msg_str ();
static int expect_msg ();
static void init_target_mm ();
static int mm_memory_space ();
#define FREEZE_MODE (read_register(CPS_REGNUM) && 0x400)
#define USE_SHADOW_PC ((processor_type == a29k_freeze_mode) && FREEZE_MODE)
#define LLOG_FILE "minimon.log"
#if defined (LOG_FILE)
FILE *log_file;
#endif
#define BUFER_SIZE 512
#define MAXDATA_T (target_config.max_msg_size - \
offsetof(struct write_r_msg_t,data[0]))
#define MAXDATA_H (BUFER_SIZE - offsetof(struct write_r_msg_t,data[0]))
#define MAXDATA (MAXDATA_H < MAXDATA_T ? MAXDATA_H : MAXDATA_T)
static char out_buf[BUFER_SIZE];
static char in_buf[BUFER_SIZE];
int msg_recv_serial ();
int msg_send_serial ();
#define MAX_RETRIES 5000
extern struct target_ops mm_ops;
struct config_msg_t target_config;
union msg_t *out_msg_buf = (union msg_t *) out_buf;
union msg_t *in_msg_buf = (union msg_t *) in_buf;
static int timeout = 5;
int mm_desc = -1;
FILE *mm_stream;
#ifndef HAVE_TERMIO
#ifndef __STDC__
#ifndef volatile
#define volatile
# endif
#endif
volatile int n_alarms;
static void
mm_timer (void)
{
#if 0
if (kiodebug)
printf ("mm_timer called\n");
#endif
n_alarms++;
}
#endif
static char *prog_name = NULL;
static void
mm_create_inferior (char *execfile, char *args, char **env)
{
#define MAX_TOKENS 25
#define BUFFER_SIZE 256
int token_count;
int result;
char *token[MAX_TOKENS];
char cmd_line[BUFFER_SIZE];
if (args && *args)
error ("Can't pass arguments to remote mm process (yet).");
if (execfile == 0 )
error ("No executable file specified");
if (!mm_stream)
{
printf ("Minimon not open yet.\n");
return;
}
printf_filtered ("\n\
Assuming you are at NYU debuging a kernel, i.e., no need to download.\n\n");
init_wait_for_inferior ();
clear_proceed_status ();
stop_soon_quietly = 1;
proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
normal_stop ();
}
static void
mm_mourn (void)
{
pop_target ();
generic_mourn_inferior ();
}
#ifndef B19200
#define B19200 EXTA
#endif
#ifndef B38400
#define B38400 EXTB
#endif
static struct
{
int rate, damn_b;
}
baudtab[] =
{
{
0, B0
}
,
{
50, B50
}
,
{
75, B75
}
,
{
110, B110
}
,
{
134, B134
}
,
{
150, B150
}
,
{
200, B200
}
,
{
300, B300
}
,
{
600, B600
}
,
{
1200, B1200
}
,
{
1800, B1800
}
,
{
2400, B2400
}
,
{
4800, B4800
}
,
{
9600, B9600
}
,
{
19200, B19200
}
,
{
38400, B38400
}
,
{
-1, -1
}
,
};
static int
damn_b (int rate)
{
int i;
for (i = 0; baudtab[i].rate != -1; i++)
if (rate == baudtab[i].rate)
return baudtab[i].damn_b;
return B38400;
}
static char *dev_name;
int baudrate = 9600;
static void
mm_open (char *name, int from_tty)
{
TERMINAL sg;
unsigned int prl;
char *p;
for (p = name;
p && *p && !isspace (*p); p++)
;
if (p == 0 || *p == '\0')
erroid:
error ("Usage : <command> <serial-device> <baud-rate> [progname]");
dev_name = (char *) xmalloc (p - name + 1);
strncpy (dev_name, name, p - name);
dev_name[p - name] = '\0';
for (; isspace (*p); p++)
;
if (1 != sscanf (p, "%d ", &baudrate))
goto erroid;
for (; isdigit (*p); p++)
;
for (; isspace (*p); p++)
;
if (prog_name != NULL)
free (prog_name);
prog_name = savestring (p, strlen (p));
if (mm_desc >= 0)
close (mm_desc);
mm_desc = open (dev_name, O_RDWR);
if (mm_desc < 0)
perror_with_name (dev_name);
ioctl (mm_desc, TIOCGETP, &sg);
#ifdef HAVE_TERMIO
sg.c_cc[VMIN] = 0;
sg.c_cc[VTIME] = timeout * 10;
sg.c_lflag &= ~(ICANON | ECHO);
sg.c_cflag = (sg.c_cflag & ~CBAUD) | damn_b (baudrate);
#else
sg.sg_ispeed = damn_b (baudrate);
sg.sg_ospeed = damn_b (baudrate);
sg.sg_flags |= RAW;
sg.sg_flags |= ANYP;
sg.sg_flags &= ~ECHO;
#endif
ioctl (mm_desc, TIOCSETP, &sg);
mm_stream = fdopen (mm_desc, "r+");
push_target (&mm_ops);
#ifndef HAVE_TERMIO
#ifndef NO_SIGINTERRUPT
if (siginterrupt (SIGALRM, 1) != 0)
perror ("mm_open: error in siginterrupt");
#endif
if ((void (*)) signal (SIGALRM, mm_timer) == (void (*)) -1)
perror ("mm_open: error in signal");
#endif
#if defined (LOG_FILE)
log_file = fopen (LOG_FILE, "w");
if (log_file == NULL)
perror_with_name (LOG_FILE);
#endif
DRAIN_INPUT ();
out_msg_buf->config_req_msg.code = CONFIG_REQ;
out_msg_buf->config_req_msg.length = 4 * 0;
msg_send_serial (out_msg_buf);
expect_msg (CONFIG, in_msg_buf, 1);
a29k_get_processor_type ();
printf_filtered ("Connected to MiniMon via %s.\n", dev_name);
printf_filtered ("Remote debugging using virtual addresses works only\n");
printf_filtered ("\twhen virtual addresses map 1:1 to physical addresses.\n")
;
if (processor_type != a29k_freeze_mode)
{
fprintf_filtered (gdb_stderr,
"Freeze-mode debugging not available, and can only be done on an A29050.\n");
}
target_config.code = CONFIG;
target_config.length = 0;
target_config.processor_id = in_msg_buf->config_msg.processor_id;
target_config.version = in_msg_buf->config_msg.version;
target_config.I_mem_start = in_msg_buf->config_msg.I_mem_start;
target_config.I_mem_size = in_msg_buf->config_msg.I_mem_size;
target_config.D_mem_start = in_msg_buf->config_msg.D_mem_start;
target_config.D_mem_size = in_msg_buf->config_msg.D_mem_size;
target_config.ROM_start = in_msg_buf->config_msg.ROM_start;
target_config.ROM_size = in_msg_buf->config_msg.ROM_size;
target_config.max_msg_size = in_msg_buf->config_msg.max_msg_size;
target_config.max_bkpts = in_msg_buf->config_msg.max_bkpts;
target_config.coprocessor = in_msg_buf->config_msg.coprocessor;
target_config.reserved = in_msg_buf->config_msg.reserved;
if (from_tty)
{
printf ("Connected to MiniMON :\n");
printf (" Debugcore version %d.%d\n",
0x0f & (target_config.version >> 4),
0x0f & (target_config.version));
printf (" Configuration version %d.%d\n",
0x0f & (target_config.version >> 12),
0x0f & (target_config.version >> 8));
printf (" Message system version %d.%d\n",
0x0f & (target_config.version >> 20),
0x0f & (target_config.version >> 16));
printf (" Communication driver version %d.%d\n",
0x0f & (target_config.version >> 28),
0x0f & (target_config.version >> 24));
}
out_msg_buf->go_msg.code = GO;
out_msg_buf->go_msg.length = 0;
msg_send_serial (out_msg_buf);
}
static void
mm_close (
int quitting)
{
if (mm_desc < 0)
error ("Can't close remote connection: not debugging remotely.");
DRAIN_INPUT ();
fclose (mm_stream);
mm_stream = NULL;
mm_desc = -1;
#if defined (LOG_FILE)
if (ferror (log_file))
printf ("Error writing log file.\n");
if (fclose (log_file) != 0)
printf ("Error closing log file.\n");
#endif
printf ("Ending remote debugging\n");
}
static void
mm_attach (char *args, int from_tty)
{
if (!mm_stream)
error ("MiniMon not opened yet, use the 'target minimon' command.\n");
if (from_tty)
printf ("Attaching to remote program %s...\n", prog_name);
out_msg_buf->go_msg.code = GO;
out_msg_buf->go_msg.length = 0;
msg_send_serial (out_msg_buf);
sleep (2);
out_msg_buf->break_msg.code = BREAK;
out_msg_buf->break_msg.length = 0;
msg_send_serial (out_msg_buf);
}
static void
mm_detach (char *args, int from_tty)
{
remove_breakpoints ();
out_msg_buf->go_msg.code = GO;
out_msg_buf->go_msg.length = 0;
msg_send_serial (out_msg_buf);
pop_target ();
}
static void
mm_resume (int pid, int step, enum target_signal sig)
{
if (sig != TARGET_SIGNAL_0)
warning ("Can't send signals to a remote MiniMon system.");
if (step)
{
out_msg_buf->step_msg.code = STEP;
out_msg_buf->step_msg.length = 1 * 4;
out_msg_buf->step_msg.count = 1;
msg_send_serial (out_msg_buf);
}
else
{
out_msg_buf->go_msg.code = GO;
out_msg_buf->go_msg.length = 0;
msg_send_serial (out_msg_buf);
}
}
static int
mm_wait (struct target_waitstatus *status)
{
int i, result;
int old_timeout = timeout;
int old_immediate_quit = immediate_quit;
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
timeout = 0;
immediate_quit = 1;
while (1)
{
while (msg_recv_serial (in_msg_buf))
{
QUIT;
}
switch (in_msg_buf->halt_msg.code)
{
case HIF_CALL:
i = in_msg_buf->hif_call_rtn_msg.service_number;
result = service_HIF (in_msg_buf);
if (i == 1)
goto exit;
if (result)
printf ("Warning: failure during HIF service %d\n", i);
break;
case CHANNEL0_ACK:
service_HIF (in_msg_buf);
break;
case CHANNEL1:
i = in_msg_buf->channel1_msg.length;
in_msg_buf->channel1_msg.data[i] = '\0';
printf ("%s", in_msg_buf->channel1_msg.data);
gdb_flush (gdb_stdout);
out_msg_buf->channel1_ack_msg.code = CHANNEL1_ACK;
out_msg_buf->channel1_ack_msg.length = 0;
result = msg_send_serial (out_msg_buf);
break;
case HALT:
goto halted;
default:
goto halted;
}
}
halted:
if (in_msg_buf->halt_msg.trap_number == 0)
{
printf ("Am290*0 received vector number %d (break point)\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
}
else if (in_msg_buf->halt_msg.trap_number == 1)
{
printf ("Am290*0 received vector number %d\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_BUS;
}
else if (in_msg_buf->halt_msg.trap_number == 3
|| in_msg_buf->halt_msg.trap_number == 4)
{
printf ("Am290*0 received vector number %d\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_FPE;
}
else if (in_msg_buf->halt_msg.trap_number == 5)
{
printf ("Am290*0 received vector number %d\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_ILL;
}
else if (in_msg_buf->halt_msg.trap_number >= 6
&& in_msg_buf->halt_msg.trap_number <= 11)
{
printf ("Am290*0 received vector number %d\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_SEGV;
}
else if (in_msg_buf->halt_msg.trap_number == 12
|| in_msg_buf->halt_msg.trap_number == 13)
{
printf ("Am290*0 received vector number %d\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_ILL;
}
else if (in_msg_buf->halt_msg.trap_number == 14)
{
printf ("Am290*0 received vector number %d\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_ALRM;
}
else if (in_msg_buf->halt_msg.trap_number == 15)
{
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
}
else if (in_msg_buf->halt_msg.trap_number >= 16
&& in_msg_buf->halt_msg.trap_number <= 21)
{
printf ("Am290*0 received vector number %d\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_INT;
}
else if (in_msg_buf->halt_msg.trap_number == 22)
{
printf ("Am290*0 received vector number %d\n",
in_msg_buf->halt_msg.trap_number);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_ILL;
}
else if (in_msg_buf->halt_msg.trap_number == 75)
{
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
}
else
exit:
{
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
}
timeout = old_timeout;
immediate_quit = old_immediate_quit;
return 0;
}
static void
mm_fetch_registers (int regno)
{
INT32 *data_p;
if (regno >= 0)
{
fetch_register (regno);
return;
}
out_msg_buf->read_req_msg.byte_count = 4 * 1;
out_msg_buf->read_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->read_req_msg.address = 1;
msg_send_serial (out_msg_buf);
expect_msg (READ_ACK, in_msg_buf, 1);
data_p = &(in_msg_buf->read_r_ack_msg.data[0]);
supply_register (GR1_REGNUM, data_p);
#if defined(GR64_REGNUM)
out_msg_buf->read_req_msg.code = READ_REQ;
out_msg_buf->read_req_msg.length = 4 * 3;
out_msg_buf->read_req_msg.byte_count = 4 * 32;
out_msg_buf->read_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->read_req_msg.address = 64;
msg_send_serial (out_msg_buf);
expect_msg (READ_ACK, in_msg_buf, 1);
data_p = &(in_msg_buf->read_r_ack_msg.data[0]);
for (regno = GR64_REGNUM; regno < GR64_REGNUM + 32; regno++)
{
supply_register (regno, data_p++);
}
#endif
out_msg_buf->read_req_msg.code = READ_REQ;
out_msg_buf->read_req_msg.length = 4 * 3;
out_msg_buf->read_req_msg.byte_count = 4 * 32;
out_msg_buf->read_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->read_req_msg.address = 96;
msg_send_serial (out_msg_buf);
expect_msg (READ_ACK, in_msg_buf, 1);
data_p = &(in_msg_buf->read_r_ack_msg.data[0]);
for (regno = GR96_REGNUM; regno < GR96_REGNUM + 32; regno++)
{
supply_register (regno, data_p++);
}
out_msg_buf->read_req_msg.byte_count = 4 * (128);
out_msg_buf->read_req_msg.memory_space = LOCAL_REG;
out_msg_buf->read_req_msg.address = 0;
msg_send_serial (out_msg_buf);
expect_msg (READ_ACK, in_msg_buf, 1);
data_p = &(in_msg_buf->read_r_ack_msg.data[0]);
for (regno = LR0_REGNUM; regno < LR0_REGNUM + 128; regno++)
{
supply_register (regno, data_p++);
}
out_msg_buf->read_req_msg.byte_count = 4 * 15;
out_msg_buf->read_req_msg.memory_space = SPECIAL_REG;
out_msg_buf->read_req_msg.address = 0;
msg_send_serial (out_msg_buf);
expect_msg (READ_ACK, in_msg_buf, 1);
data_p = &(in_msg_buf->read_r_ack_msg.data[0]);
for (regno = 0; regno <= 14; regno++)
{
supply_register (SR_REGNUM (regno), data_p++);
}
if (USE_SHADOW_PC)
{
fetch_register (NPC_REGNUM);
fetch_register (PC_REGNUM);
fetch_register (PC2_REGNUM);
}
out_msg_buf->read_req_msg.byte_count = 4 * 8;
out_msg_buf->read_req_msg.memory_space = SPECIAL_REG;
out_msg_buf->read_req_msg.address = 128;
msg_send_serial (out_msg_buf);
expect_msg (READ_ACK, in_msg_buf, 1);
data_p = &(in_msg_buf->read_r_ack_msg.data[0]);
for (regno = 128; regno <= 135; regno++)
{
supply_register (SR_REGNUM (regno), data_p++);
}
{
int val = -1;
supply_register (FPE_REGNUM, &val);
supply_register (INTE_REGNUM, &val);
supply_register (FPS_REGNUM, &val);
supply_register (EXO_REGNUM, &val);
}
}
static void
mm_store_registers (int regno)
{
int result;
if (regno >= 0)
{
store_register (regno);
return;
}
result = 0;
out_msg_buf->write_r_msg.code = WRITE_REQ;
out_msg_buf->write_r_msg.byte_count = 4 * 1;
out_msg_buf->write_r_msg.length = 3 * 4 + out_msg_buf->write_r_msg.byte_count;
out_msg_buf->write_r_msg.memory_space = GLOBAL_REG;
out_msg_buf->write_r_msg.address = 1;
out_msg_buf->write_r_msg.data[0] = read_register (GR1_REGNUM);
msg_send_serial (out_msg_buf);
if (!expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = -1;
}
#if defined(GR64_REGNUM)
out_msg_buf->write_r_msg.byte_count = 4 * (32);
out_msg_buf->write_r_msg.length = 3 * 4 + out_msg_buf->write_r_msg.byte_count;
out_msg_buf->write_r_msg.address = 64;
for (regno = GR64_REGNUM; regno < GR64_REGNUM + 32; regno++)
{
out_msg_buf->write_r_msg.data[regno - GR64_REGNUM] = read_register (regno);
}
msg_send_serial (out_msg_buf);
if (!expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = -1;
}
#endif
out_msg_buf->write_r_msg.byte_count = 4 * (32);
out_msg_buf->write_r_msg.length = 3 * 4 + out_msg_buf->write_r_msg.byte_count;
out_msg_buf->write_r_msg.address = 96;
for (regno = GR96_REGNUM; regno < GR96_REGNUM + 32; regno++)
{
out_msg_buf->write_r_msg.data[regno - GR96_REGNUM] = read_register (regno);
}
msg_send_serial (out_msg_buf);
if (!expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = -1;
}
out_msg_buf->write_r_msg.memory_space = LOCAL_REG;
out_msg_buf->write_r_msg.byte_count = 4 * 128;
out_msg_buf->write_r_msg.length = 3 * 4 + out_msg_buf->write_r_msg.byte_count;
out_msg_buf->write_r_msg.address = 0;
for (regno = LR0_REGNUM; regno < LR0_REGNUM + 128; regno++)
{
out_msg_buf->write_r_msg.data[regno - LR0_REGNUM] = read_register (regno);
}
msg_send_serial (out_msg_buf);
if (!expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = -1;
}
out_msg_buf->write_r_msg.memory_space = SPECIAL_REG;
out_msg_buf->write_r_msg.byte_count = 4 * 10;
out_msg_buf->write_r_msg.length = 3 * 4 + out_msg_buf->write_r_msg.byte_count;
out_msg_buf->write_r_msg.address = 0;
for (regno = 0; regno <= 9; regno++)
out_msg_buf->write_r_msg.data[regno] = read_register (SR_REGNUM (regno));
msg_send_serial (out_msg_buf);
if (!expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = -1;
}
out_msg_buf->write_r_msg.byte_count = 4 * 3;
out_msg_buf->write_r_msg.length = 3 * 4 + out_msg_buf->write_r_msg.byte_count;
for (regno = 10; regno <= 12; regno++)
out_msg_buf->write_r_msg.data[regno - 10] = read_register (SR_REGNUM (regno));
if (USE_SHADOW_PC)
out_msg_buf->write_r_msg.address = 20;
else
out_msg_buf->write_r_msg.address = 10;
msg_send_serial (out_msg_buf);
if (!expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = -1;
}
out_msg_buf->write_r_msg.byte_count = 4 * 2;
out_msg_buf->write_r_msg.length = 3 * 4 + out_msg_buf->write_r_msg.byte_count;
out_msg_buf->write_r_msg.address = 13;
for (regno = 13; regno <= 14; regno++)
out_msg_buf->write_r_msg.data[regno - 13] = read_register (SR_REGNUM (regno));
msg_send_serial (out_msg_buf);
if (!expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = -1;
}
out_msg_buf->write_r_msg.byte_count = 4 * 8;
out_msg_buf->write_r_msg.length = 3 * 4 + out_msg_buf->write_r_msg.byte_count;
out_msg_buf->write_r_msg.address = 128;
for (regno = 128; regno <= 135; regno++)
out_msg_buf->write_r_msg.data[regno - 128] = read_register (SR_REGNUM (regno));
msg_send_serial (out_msg_buf);
if (!expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = -1;
}
registers_changed ();
}
static void
mm_prepare_to_store (void)
{
}
static CORE_ADDR
translate_addr (CORE_ADDR addr)
{
#if defined(KERNEL_DEBUGGING)
if (addr >= UVADDR)
{
CORE_ADDR i = (CORE_ADDR) read_register (PADDR_U_REGNUM);
return (i + addr - (CORE_ADDR) UVADDR);
}
else
{
return (addr);
}
#else
return (addr);
#endif
}
static void
mm_files_info (void)
{
printf ("\tAttached to %s at %d baud and running program %s.\n",
dev_name, baudrate, prog_name);
}
static int
mm_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
{
out_msg_buf->bkpt_set_msg.code = BKPT_SET;
out_msg_buf->bkpt_set_msg.length = 4 * 4;
out_msg_buf->bkpt_set_msg.memory_space = I_MEM;
out_msg_buf->bkpt_set_msg.bkpt_addr = (ADDR32) addr;
out_msg_buf->bkpt_set_msg.pass_count = 1;
out_msg_buf->bkpt_set_msg.bkpt_type = -1;
msg_send_serial (out_msg_buf);
if (expect_msg (BKPT_SET_ACK, in_msg_buf, 1))
{
return 0;
}
else
{
return 1;
}
}
static int
mm_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
{
out_msg_buf->bkpt_rm_msg.code = BKPT_RM;
out_msg_buf->bkpt_rm_msg.length = 4 * 3;
out_msg_buf->bkpt_rm_msg.memory_space = I_MEM;
out_msg_buf->bkpt_rm_msg.bkpt_addr = (ADDR32) addr;
msg_send_serial (out_msg_buf);
if (expect_msg (BKPT_RM_ACK, in_msg_buf, 1))
{
return 0;
}
else
{
return 1;
}
}
static void
mm_kill (char *arg, int from_tty)
{
char buf[4];
#if defined(KERNEL_DEBUGGING)
if (from_tty)
{
printf ("Kernel not killed, but left in current state.\n");
printf ("Use detach to leave kernel running.\n");
}
#else
out_msg_buf->break_msg.code = BREAK;
out_msg_buf->bkpt_set_msg.length = 4 * 0;
expect_msg (HALT, in_msg_buf, from_tty);
if (from_tty)
{
printf ("Target has been stopped.");
printf ("Would you like to do a hardware reset (y/n) [n] ");
fgets (buf, 3, stdin);
if (buf[0] == 'y')
{
out_msg_buf->reset_msg.code = RESET;
out_msg_buf->bkpt_set_msg.length = 4 * 0;
expect_msg (RESET_ACK, in_msg_buf, from_tty);
printf ("Target has been reset.");
}
}
pop_target ();
#endif
}
static void
mm_load (char *arg_string, int from_tty)
{
dont_repeat ();
#if defined(KERNEL_DEBUGGING)
printf ("The kernel had better be loaded already! Loading not done.\n");
#else
if (arg_string == 0)
error ("The load command takes a file name");
arg_string = tilde_expand (arg_string);
make_cleanup (free, arg_string);
QUIT;
immediate_quit++;
error ("File loading is not yet supported for MiniMon.");
immediate_quit--;
#endif
}
static int
mm_write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
int i, nwritten;
out_msg_buf->write_req_msg.code = WRITE_REQ;
out_msg_buf->write_req_msg.memory_space = mm_memory_space (memaddr);
nwritten = 0;
while (nwritten < len)
{
int num_to_write = len - nwritten;
if (num_to_write > MAXDATA)
num_to_write = MAXDATA;
for (i = 0; i < num_to_write; i++)
out_msg_buf->write_req_msg.data[i] = myaddr[i + nwritten];
out_msg_buf->write_req_msg.byte_count = num_to_write;
out_msg_buf->write_req_msg.length = 3 * 4 + num_to_write;
out_msg_buf->write_req_msg.address = memaddr + nwritten;
msg_send_serial (out_msg_buf);
if (expect_msg (WRITE_ACK, in_msg_buf, 1))
{
nwritten += in_msg_buf->write_ack_msg.byte_count;
}
else
{
break;
}
}
return (nwritten);
}
static int
mm_read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
int i, nread;
out_msg_buf->read_req_msg.code = READ_REQ;
out_msg_buf->read_req_msg.memory_space = mm_memory_space (memaddr);
nread = 0;
while (nread < len)
{
int num_to_read = (len - nread);
if (num_to_read > MAXDATA)
num_to_read = MAXDATA;
out_msg_buf->read_req_msg.byte_count = num_to_read;
out_msg_buf->read_req_msg.length = 3 * 4 + num_to_read;
out_msg_buf->read_req_msg.address = memaddr + nread;
msg_send_serial (out_msg_buf);
if (expect_msg (READ_ACK, in_msg_buf, 1))
{
for (i = 0; i < in_msg_buf->read_ack_msg.byte_count; i++)
myaddr[i + nread] = in_msg_buf->read_ack_msg.data[i];
nread += in_msg_buf->read_ack_msg.byte_count;
}
else
{
break;
}
}
return (nread);
}
static int
mm_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len, int write)
{
memaddr = translate_addr (memaddr);
if (write)
return mm_write_inferior_memory (memaddr, myaddr, len);
else
return mm_read_inferior_memory (memaddr, myaddr, len);
}
int
msg_send_serial (union msg_t *msg_ptr)
{
INT32 message_size;
int byte_count;
int result;
char c;
byte_count = 0;
message_size = msg_ptr->generic_msg.length + (2 * sizeof (INT32));
do
{
c = *((char *) msg_ptr + byte_count);
result = write (mm_desc, &c, 1);
if (result == 1)
{
byte_count = byte_count + 1;
}
}
while ((byte_count < message_size));
return (0);
}
int
msg_recv_serial (union msg_t *msg_ptr)
{
static INT32 length = 0;
static INT32 byte_count = 0;
int result;
char c;
if (msg_ptr == 0)
{
length = 0;
byte_count = 0;
#ifdef HAVE_TERMIO
->"timeout==0 semantics not supported"
read (mm_desc, in_buf, BUFER_SIZE);
#else
alarm (1);
read (mm_desc, in_buf, BUFER_SIZE);
alarm (0);
#endif
return (0);
}
#ifdef HAVE_TERMIO
->"timeout==0 semantics not supported (and its nice if they are)"
result = read (mm_desc, &c, 1);
#else
alarm (timeout);
result = read (mm_desc, &c, 1);
alarm (0);
#endif
if (result < 0)
{
if (errno == EINTR)
{
error ("Timeout reading from remote system.");
}
else
perror_with_name ("remote");
}
else if (result == 1)
{
*((char *) msg_ptr + byte_count) = c;
byte_count = byte_count + 1;
}
if (byte_count == (2 * sizeof (INT32)))
length = msg_ptr->generic_msg.length;
if (byte_count >= (length + (2 * sizeof (INT32))))
{
byte_count = 0;
return (0);
}
else
return (-1);
}
TERMINAL kbd_tbuf;
int
kbd_raw (void)
{
int result;
TERMINAL tbuf;
#ifdef HAVE_TERMIO
result = ioctl (0, TCGETA, &kbd_tbuf);
#else
result = ioctl (0, TIOCGETP, &kbd_tbuf);
#endif
if (result == -1)
return (errno);
#ifdef HAVE_TERMIO
result = ioctl (0, TCGETA, &tbuf);
#else
result = ioctl (0, TIOCGETP, &tbuf);
#endif
if (result == -1)
return (errno);
#ifdef HAVE_TERMIO
tbuf.c_iflag = tbuf.c_iflag &
~(INLCR | ICRNL | IUCLC | ISTRIP | IXON | BRKINT);
tbuf.c_lflag = tbuf.c_lflag & ~(ICANON | ISIG | ECHO);
tbuf.c_cc[4] = 0;
tbuf.c_cc[5] = 0;
#else
tbuf.sg_flags |= RAW;
tbuf.sg_flags |= ANYP;
tbuf.sg_flags &= ~ECHO;
#endif
#ifdef HAVE_TERMIO
result = ioctl (0, TCSETAF, &tbuf);
#else
result = ioctl (0, TIOCSETP, &tbuf);
#endif
if (result == -1)
return (errno);
return (0);
}
int
kbd_restore (void)
{
int result;
#ifdef HAVE_TERMIO
result = ioctl (0, TCSETAF, &kbd_tbuf);
#else
result = ioctl (0, TIOCGETP, &kbd_tbuf);
#endif
if (result == -1)
return (errno);
return (0);
}
static int
fetch_register (int regno)
{
int result;
out_msg_buf->read_req_msg.code = READ_REQ;
out_msg_buf->read_req_msg.length = 4 * 3;
out_msg_buf->read_req_msg.byte_count = 4;
if (regno == GR1_REGNUM)
{
out_msg_buf->read_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->read_req_msg.address = 1;
}
else if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32)
{
out_msg_buf->read_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->read_req_msg.address = (regno - GR96_REGNUM) + 96;
}
#if defined(GR64_REGNUM)
else if (regno >= GR64_REGNUM && regno < GR64_REGNUM + 32)
{
out_msg_buf->read_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->read_req_msg.address = (regno - GR64_REGNUM) + 64;
}
#endif
else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128)
{
out_msg_buf->read_req_msg.memory_space = LOCAL_REG;
out_msg_buf->read_req_msg.address = (regno - LR0_REGNUM);
}
else if (regno >= FPE_REGNUM && regno <= EXO_REGNUM)
{
int val = -1;
supply_register (160 + (regno - FPE_REGNUM), &val);
return 0;
}
else
{
out_msg_buf->read_req_msg.memory_space = SPECIAL_REG;
out_msg_buf->read_req_msg.address = regnum_to_srnum (regno);
}
msg_send_serial (out_msg_buf);
if (expect_msg (READ_ACK, in_msg_buf, 1))
{
supply_register (regno, &(in_msg_buf->read_r_ack_msg.data[0]));
result = 0;
}
else
{
result = -1;
}
return result;
}
static int
store_register (int regno)
{
int result;
out_msg_buf->write_req_msg.code = WRITE_REQ;
out_msg_buf->write_req_msg.length = 4 * 4;
out_msg_buf->write_req_msg.byte_count = 4;
out_msg_buf->write_r_msg.data[0] = read_register (regno);
if (regno == GR1_REGNUM)
{
out_msg_buf->write_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->write_req_msg.address = 1;
registers_changed ();
}
#if defined(GR64_REGNUM)
else if (regno >= GR64_REGNUM && regno < GR64_REGNUM + 32)
{
out_msg_buf->write_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->write_req_msg.address = (regno - GR64_REGNUM) + 64;
}
#endif
else if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32)
{
out_msg_buf->write_req_msg.memory_space = GLOBAL_REG;
out_msg_buf->write_req_msg.address = (regno - GR96_REGNUM) + 96;
}
else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128)
{
out_msg_buf->write_req_msg.memory_space = LOCAL_REG;
out_msg_buf->write_req_msg.address = (regno - LR0_REGNUM);
}
else if (regno >= FPE_REGNUM && regno <= EXO_REGNUM)
{
return 0;
}
else
{
out_msg_buf->write_req_msg.memory_space = SPECIAL_REG;
out_msg_buf->write_req_msg.address = regnum_to_srnum (regno);
}
msg_send_serial (out_msg_buf);
if (expect_msg (WRITE_ACK, in_msg_buf, 1))
{
result = 0;
}
else
{
result = -1;
}
return result;
}
static int
regnum_to_srnum (int regno)
{
switch (regno)
{
case VAB_REGNUM:
return (0);
case OPS_REGNUM:
return (1);
case CPS_REGNUM:
return (2);
case CFG_REGNUM:
return (3);
case CHA_REGNUM:
return (4);
case CHD_REGNUM:
return (5);
case CHC_REGNUM:
return (6);
case RBP_REGNUM:
return (7);
case TMC_REGNUM:
return (8);
case TMR_REGNUM:
return (9);
case NPC_REGNUM:
return (USE_SHADOW_PC ? (20) : (10));
case PC_REGNUM:
return (USE_SHADOW_PC ? (21) : (11));
case PC2_REGNUM:
return (USE_SHADOW_PC ? (22) : (12));
case MMU_REGNUM:
return (13);
case LRU_REGNUM:
return (14);
case IPC_REGNUM:
return (128);
case IPA_REGNUM:
return (129);
case IPB_REGNUM:
return (130);
case Q_REGNUM:
return (131);
case ALU_REGNUM:
return (132);
case BP_REGNUM:
return (133);
case FC_REGNUM:
return (134);
case CR_REGNUM:
return (135);
case FPE_REGNUM:
return (160);
case INTE_REGNUM:
return (161);
case FPS_REGNUM:
return (162);
case EXO_REGNUM:
return (164);
default:
return (255);
}
}
static void
init_target_mm (ADDR32 tstart, ADDR32 tend, ADDR32 dstart, ADDR32 dend,
ADDR32 entry, INT32 ms_size, INT32 rs_size, ADDR32 arg_start)
{
out_msg_buf->init_msg.code = INIT;
out_msg_buf->init_msg.length = sizeof (struct init_msg_t) - 2 * sizeof (INT32);
out_msg_buf->init_msg.text_start = tstart;
out_msg_buf->init_msg.text_end = tend;
out_msg_buf->init_msg.data_start = dstart;
out_msg_buf->init_msg.data_end = dend;
out_msg_buf->init_msg.entry_point = entry;
out_msg_buf->init_msg.mem_stack_size = ms_size;
out_msg_buf->init_msg.reg_stack_size = rs_size;
out_msg_buf->init_msg.arg_start = arg_start;
msg_send_serial (out_msg_buf);
expect_msg (INIT_ACK, in_msg_buf, 1);
}
static char *
msg_str (INT32 code)
{
static char cbuf[32];
switch (code)
{
case BKPT_SET_ACK:
sprintf (cbuf, "%s (%d)", "BKPT_SET_ACK", code);
break;
case BKPT_RM_ACK:
sprintf (cbuf, "%s (%d)", "BKPT_RM_ACK", code);
break;
case INIT_ACK:
sprintf (cbuf, "%s (%d)", "INIT_ACK", code);
break;
case READ_ACK:
sprintf (cbuf, "%s (%d)", "READ_ACK", code);
break;
case WRITE_ACK:
sprintf (cbuf, "%s (%d)", "WRITE_ACK", code);
break;
case ERROR:
sprintf (cbuf, "%s (%d)", "ERROR", code);
break;
case HALT:
sprintf (cbuf, "%s (%d)", "HALT", code);
break;
default:
sprintf (cbuf, "UNKNOWN (%d)", code);
break;
}
return (cbuf);
}
static char *
error_msg_str (INT32 code)
{
static char cbuf[50];
switch (code)
{
case EMFAIL:
return ("EMFAIL: unrecoverable error");
case EMBADADDR:
return ("EMBADADDR: Illegal address");
case EMBADREG:
return ("EMBADREG: Illegal register ");
case EMACCESS:
return ("EMACCESS: Could not access memory");
case EMBADMSG:
return ("EMBADMSG: Unknown message type");
case EMMSG2BIG:
return ("EMMSG2BIG: Message to large");
case EMNOSEND:
return ("EMNOSEND: Could not send message");
case EMNORECV:
return ("EMNORECV: Could not recv message");
case EMRESET:
return ("EMRESET: Could not RESET target");
case EMCONFIG:
return ("EMCONFIG: Could not get target CONFIG");
case EMSTATUS:
return ("EMSTATUS: Could not get target STATUS");
case EMREAD:
return ("EMREAD: Could not READ target memory");
case EMWRITE:
return ("EMWRITE: Could not WRITE target memory");
case EMBKPTSET:
return ("EMBKPTSET: Could not set breakpoint");
case EMBKPTRM:
return ("EMBKPTRM: Could not remove breakpoint");
case EMBKPTSTAT:
return ("EMBKPTSTAT: Could not get breakpoint status");
case EMBKPTNONE:
return ("EMBKPTNONE: All breakpoints in use");
case EMBKPTUSED:
return ("EMBKPTUSED: Breakpoints already in use");
case EMINIT:
return ("EMINIT: Could not init target memory");
case EMGO:
return ("EMGO: Could not start execution");
case EMSTEP:
return ("EMSTEP: Could not single step");
case EMBREAK:
return ("EMBREAK: Could not BREAK");
case EMCOMMERR:
return ("EMCOMMERR: Communication error");
default:
sprintf (cbuf, "error number %d", code);
break;
}
return (cbuf);
}
static int
expect_msg (INT32 msgcode, union msg_t *msg_buf, int from_tty)
{
int retries = 0;
while (msg_recv_serial (msg_buf) && (retries++ < MAX_RETRIES));
if (retries >= MAX_RETRIES)
{
printf ("Expected msg %s, ", msg_str (msgcode));
printf ("no message received!\n");
return (0);
}
if (msg_buf->generic_msg.code != msgcode)
{
if (from_tty)
{
printf ("Expected msg %s, ", msg_str (msgcode));
printf ("got msg %s\n", msg_str (msg_buf->generic_msg.code));
if (msg_buf->generic_msg.code == ERROR)
printf ("%s\n", error_msg_str (msg_buf->error_msg.error_code));
}
return (0);
}
return (1);
}
static int
mm_memory_space (CORE_ADDR *addr)
{
ADDR32 tstart = target_config.I_mem_start;
ADDR32 tend = tstart + target_config.I_mem_size;
ADDR32 dstart = target_config.D_mem_start;
ADDR32 dend = tstart + target_config.D_mem_size;
ADDR32 rstart = target_config.ROM_start;
ADDR32 rend = tstart + target_config.ROM_size;
if (((ADDR32) addr >= tstart) && ((ADDR32) addr < tend))
{
return I_MEM;
}
else if (((ADDR32) addr >= dstart) && ((ADDR32) addr < dend))
{
return D_MEM;
}
else if (((ADDR32) addr >= rstart) && ((ADDR32) addr < rend))
{
return D_ROM;
}
else
return D_MEM;
}
struct target_ops mm_ops;
static void
init_mm_ops (void)
{
mm_ops.to_shortname = "minimon";
mm_ops.to_longname = "Remote AMD/Minimon target";
mm_ops.to_doc = "Remote debug an AMD 290*0 using the MiniMon dbg core on the target";
mm_ops.to_open = mm_open;
mm_ops.to_close = mm_close;
mm_ops.to_attach = mm_attach;
mm_ops.to_post_attach = NULL;
mm_ops.to_require_attach = NULL;
mm_ops.to_detach = mm_detach;
mm_ops.to_require_detach = NULL;
mm_ops.to_resume = mm_resume;
mm_ops.to_wait = mm_wait;
mm_ops.to_post_wait = NULL;
mm_ops.to_fetch_registers = mm_fetch_registers;
mm_ops.to_store_registers = mm_store_registers;
mm_ops.to_prepare_to_store = mm_prepare_to_store;
mm_ops.to_xfer_memory = mm_xfer_inferior_memory;
mm_ops.to_files_info = mm_files_info;
mm_ops.to_insert_breakpoint = mm_insert_breakpoint;
mm_ops.to_remove_breakpoint = mm_remove_breakpoint;
mm_ops.to_terminal_init = 0;
mm_ops.to_terminal_inferior = 0;
mm_ops.to_terminal_ours_for_output = 0;
mm_ops.to_terminal_ours = 0;
mm_ops.to_terminal_info = 0;
mm_ops.to_kill = mm_kill;
mm_ops.to_load = mm_load;
mm_ops.to_lookup_symbol = 0;
mm_ops.to_create_inferior = mm_create_inferior;
mm_ops.to_post_startup_inferior = NULL;
mm_ops.to_acknowledge_created_inferior = NULL;
mm_ops.to_clone_and_follow_inferior = NULL;
mm_ops.to_post_follow_inferior_by_clone = NULL;
mm_ops.to_insert_fork_catchpoint = NULL;
mm_ops.to_remove_fork_catchpoint = NULL;
mm_ops.to_insert_vfork_catchpoint = NULL;
mm_ops.to_remove_vfork_catchpoint = NULL;
mm_ops.to_has_forked = NULL;
mm_ops.to_has_vforked = NULL;
mm_ops.to_can_follow_vfork_prior_to_exec = NULL;
mm_ops.to_post_follow_vfork = NULL;
mm_ops.to_insert_exec_catchpoint = NULL;
mm_ops.to_remove_exec_catchpoint = NULL;
mm_ops.to_has_execd = NULL;
mm_ops.to_reported_exec_events_per_exec_call = NULL;
mm_ops.to_has_exited = NULL;
mm_ops.to_mourn_inferior = mm_mourn;
mm_ops.to_can_run = 0;
mm_ops.to_notice_signals = 0;
mm_ops.to_thread_alive = 0;
mm_ops.to_stop = 0;
mm_ops.to_pid_to_exec_file = NULL;
mm_ops.to_core_file_to_sym_file = NULL;
mm_ops.to_stratum = process_stratum;
mm_ops.DONT_USE = 0;
mm_ops.to_has_all_memory = 1;
mm_ops.to_has_memory = 1;
mm_ops.to_has_stack = 1;
mm_ops.to_has_registers = 1;
mm_ops.to_has_execution = 1;
mm_ops.to_sections = 0;
mm_ops.to_sections_end = 0;
mm_ops.to_magic = OPS_MAGIC;
};
void
_initialize_remote_mm (void)
{
init_mm_ops ();
add_target (&mm_ops);
}
#ifdef NO_HIF_SUPPORT
service_HIF (union msg_t *msg)
{
return (0);
}
#endif