#include "defs.h"
#include "gdb_string.h"
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
#include "gdb_wait.h"
#include "value.h"
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include "terminal.h"
#include "target.h"
#include "gdbcore.h"
extern struct target_ops eb_ops;
static void eb_close ();
#define LOG_FILE "eb.log"
#if defined (LOG_FILE)
FILE *log_file;
#endif
static int timeout = 24;
int eb_desc = -1;
FILE *eb_stream;
static int
readchar (void)
{
char buf;
buf = '\0';
#ifdef HAVE_TERMIO
read (eb_desc, &buf, 1);
#else
alarm (timeout);
if (read (eb_desc, &buf, 1) < 0)
{
if (errno == EINTR)
error ("Timeout reading from remote system.");
else
perror_with_name ("remote");
}
alarm (0);
#endif
if (buf == '\0')
error ("Timeout reading from remote system.");
#if defined (LOG_FILE)
putc (buf & 0x7f, log_file);
#endif
return buf & 0x7f;
}
static void
expect (char *string)
{
char *p = string;
immediate_quit++;
while (1)
{
if (readchar () == *p)
{
p++;
if (*p == '\0')
{
immediate_quit--;
return;
}
}
else
p = string;
}
}
static void
expect_prompt (void)
{
#if defined (LOG_FILE)
fflush (log_file);
#endif
expect ("\n# ");
}
static int
get_hex_digit (int ignore_space)
{
int ch;
while (1)
{
ch = readchar ();
if (ch >= '0' && ch <= '9')
return ch - '0';
else if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
else if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
else if (ch == ' ' && ignore_space)
;
else
{
expect_prompt ();
error ("Invalid hex digit from remote system.");
}
}
}
static void
get_hex_byte (char *byt)
{
int val;
val = get_hex_digit (1) << 4;
val |= get_hex_digit (0);
*byt = val;
}
static void
get_hex_regs (int n, int regno)
{
long val;
int i;
for (i = 0; i < n; i++)
{
int j;
val = 0;
for (j = 0; j < 8; j++)
val = (val << 4) + get_hex_digit (j == 0);
supply_register (regno++, (char *) &val);
}
}
#ifndef HAVE_TERMIO
#ifndef __STDC__
#define volatile
#endif
volatile int n_alarms;
void
eb_timer (void)
{
#if 0
if (kiodebug)
printf ("eb_timer called\n");
#endif
n_alarms++;
}
#endif
static char *prog_name = NULL;
static int need_gi = 0;
static int need_artificial_trap = 0;
static void
eb_create_inferior (char *execfile, char *args, char **env)
{
int entry_pt;
if (args && *args)
error ("Can't pass arguments to remote EBMON process");
if (execfile == 0 || exec_bfd == 0)
error ("No executable file specified");
entry_pt = (int) bfd_get_start_address (exec_bfd);
{
fprintf (eb_stream, "YC D,0:%s", prog_name);
if (args != NULL)
fprintf (eb_stream, " %s", args);
fprintf (eb_stream, "\n");
fflush (eb_stream);
expect_prompt ();
need_gi = 1;
}
clear_proceed_status ();
init_wait_for_inferior ();
target_terminal_init ();
target_terminal_inferior ();
proceed ((CORE_ADDR) entry_pt, TARGET_SIGNAL_DEFAULT, 0);
}
#ifndef B19200
#define B19200 EXTA
#endif
#ifndef B38400
#define B38400 EXTB
#endif
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
}
,
};
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 int baudrate = 9600;
static char *dev_name;
void
eb_open (char *name, int from_tty)
{
TERMINAL sg;
char *p;
target_preopen (from_tty);
if (name == 0)
goto erroid;
for (p = name;
*p != '\0' && !isspace (*p); p++)
;
if (*p == '\0')
erroid:
error ("\
Please include the name of the device for the serial port,\n\
the baud rate, and the name of the program to run on the remote system.");
dev_name = alloca (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));
eb_close (0);
eb_desc = open (dev_name, O_RDWR);
if (eb_desc < 0)
perror_with_name (dev_name);
ioctl (eb_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 | ANYP;
sg.sg_flags &= ~ECHO;
#endif
ioctl (eb_desc, TIOCSETP, &sg);
eb_stream = fdopen (eb_desc, "r+");
push_target (&eb_ops);
if (from_tty)
printf ("Remote %s debugging %s using %s\n", target_shortname,
prog_name, dev_name);
#ifndef HAVE_TERMIO
#ifndef NO_SIGINTERRUPT
if (siginterrupt (SIGALRM, 1) != 0)
perror ("eb_open: error in siginterrupt");
#endif
if ((void (*)) signal (SIGALRM, eb_timer) == (void (*)) -1)
perror ("eb_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
write (eb_desc, "\n", 1);
expect_prompt ();
}
static void
eb_close (int quitting)
{
if (eb_stream)
fclose (eb_stream);
if (eb_desc >= 0)
eb_stream = NULL;
eb_desc = -1;
#if defined (LOG_FILE)
if (log_file)
{
if (ferror (log_file))
printf ("Error writing log file.\n");
if (fclose (log_file) != 0)
printf ("Error closing log file.\n");
}
#endif
}
void
eb_detach (int from_tty)
{
pop_target ();
if (from_tty)
printf ("Ending remote %s debugging\n", target_shortname);
}
void
eb_resume (int pid, int step, enum target_signal sig)
{
if (step)
{
write (eb_desc, "t 1,s\n", 6);
expect ("t 1,s\r");
expect ("\n@");
expect_prompt ();
need_artificial_trap = 1;
}
else
{
if (need_gi)
{
need_gi = 0;
write (eb_desc, "gi\n", 3);
expect ("gi\r");
}
else
{
write (eb_desc, "GR\n", 3);
expect ("GR\r");
}
}
}
int
eb_wait (struct target_waitstatus *status)
{
static char bpt[] = "Invalid interrupt taken - #0x50 - ";
static char exitmsg[] = "\n@????????I JMPTI GR121,LR0";
char *bp = bpt;
char *ep = exitmsg;
char swallowed[50];
char *swallowed_p = swallowed;
int ch;
int ch_handled;
int old_timeout = timeout;
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
if (need_artificial_trap != 0)
{
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
need_artificial_trap--;
return 0;
}
timeout = 0;
while (1)
{
ch_handled = 0;
ch = readchar ();
if (ch == *bp)
{
bp++;
if (*bp == '\0')
break;
ch_handled = 1;
*swallowed_p++ = ch;
}
else
bp = bpt;
if (ch == *ep || *ep == '?')
{
ep++;
if (*ep == '\0')
break;
if (!ch_handled)
*swallowed_p++ = ch;
ch_handled = 1;
}
else
ep = exitmsg;
if (!ch_handled)
{
char *p;
for (p = swallowed; p < swallowed_p; ++p)
putc (*p, stdout);
swallowed_p = swallowed;
putc (ch, stdout);
}
}
expect_prompt ();
if (*bp == '\0')
{
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = TARGET_SIGNAL_TRAP;
}
else
{
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
}
timeout = old_timeout;
return 0;
}
static char *
get_reg_name (int regno)
{
static char buf[80];
if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32)
sprintf (buf, "GR%03d", regno - GR96_REGNUM + 96);
else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128)
sprintf (buf, "LR%03d", regno - LR0_REGNUM);
else if (regno == Q_REGNUM)
strcpy (buf, "SR131");
else if (regno >= BP_REGNUM && regno <= CR_REGNUM)
sprintf (buf, "SR%03d", regno - BP_REGNUM + 133);
else if (regno == ALU_REGNUM)
strcpy (buf, "SR132");
else if (regno >= IPC_REGNUM && regno <= IPB_REGNUM)
sprintf (buf, "SR%03d", regno - IPC_REGNUM + 128);
else if (regno >= VAB_REGNUM && regno <= LRU_REGNUM)
sprintf (buf, "SR%03d", regno - VAB_REGNUM);
else if (regno == GR1_REGNUM)
strcpy (buf, "GR001");
return buf;
}
static void
eb_fetch_registers (void)
{
int reg_index;
int regnum_index;
char tempbuf[10];
int i;
#if 0
write (eb_desc, "\001\n");
expect_prompt ();
#endif
write (eb_desc, "dw gr96,gr127\n", 14);
for (reg_index = 96, regnum_index = GR96_REGNUM;
reg_index < 128;
reg_index += 4, regnum_index += 4)
{
sprintf (tempbuf, "GR%03d ", reg_index);
expect (tempbuf);
get_hex_regs (4, regnum_index);
expect ("\n");
}
for (i = 0; i < 128; i += 32)
{
sprintf (tempbuf, "dw lr%d\n", i);
write (eb_desc, tempbuf, strlen (tempbuf));
for (reg_index = i, regnum_index = LR0_REGNUM + i;
reg_index < i + 32;
reg_index += 4, regnum_index += 4)
{
sprintf (tempbuf, "LR%03d ", reg_index);
expect (tempbuf);
get_hex_regs (4, regnum_index);
expect ("\n");
}
}
write (eb_desc, "dw sr133,sr133\n", 15);
expect ("SR133 ");
get_hex_regs (1, BP_REGNUM);
expect ("\n");
write (eb_desc, "dw sr134,sr134\n", 15);
expect ("SR134 ");
get_hex_regs (1, FC_REGNUM);
expect ("\n");
write (eb_desc, "dw sr135,sr135\n", 15);
expect ("SR135 ");
get_hex_regs (1, CR_REGNUM);
expect ("\n");
write (eb_desc, "dw sr131,sr131\n", 15);
expect ("SR131 ");
get_hex_regs (1, Q_REGNUM);
expect ("\n");
write (eb_desc, "dw sr0,sr14\n", 12);
for (reg_index = 0, regnum_index = VAB_REGNUM;
regnum_index <= LRU_REGNUM;
regnum_index += 4, reg_index += 4)
{
sprintf (tempbuf, "SR%03d ", reg_index);
expect (tempbuf);
get_hex_regs (reg_index == 12 ? 3 : 4, regnum_index);
expect ("\n");
}
{
int val = -1;
supply_register (FPE_REGNUM, (char *) &val);
supply_register (INTE_REGNUM, (char *) &val);
supply_register (FPS_REGNUM, (char *) &val);
supply_register (EXO_REGNUM, (char *) &val);
}
write (eb_desc, "dw gr1,gr1\n", 11);
expect ("GR001 ");
get_hex_regs (1, GR1_REGNUM);
expect_prompt ();
}
void
eb_fetch_register (int regno)
{
if (regno == -1)
eb_fetch_registers ();
else
{
char *name = get_reg_name (regno);
fprintf (eb_stream, "dw %s,%s\n", name, name);
expect (name);
expect (" ");
get_hex_regs (1, regno);
expect_prompt ();
}
return;
}
static void
eb_store_registers (void)
{
int i, j;
fprintf (eb_stream, "s gr1,%x\n", read_register (GR1_REGNUM));
expect_prompt ();
for (j = 0; j < 32; j += 16)
{
fprintf (eb_stream, "s gr%d,", j + 96);
for (i = 0; i < 15; ++i)
fprintf (eb_stream, "%x,", read_register (GR96_REGNUM + j + i));
fprintf (eb_stream, "%x\n", read_register (GR96_REGNUM + j + 15));
expect_prompt ();
}
for (j = 0; j < 128; j += 16)
{
fprintf (eb_stream, "s lr%d,", j);
for (i = 0; i < 15; ++i)
fprintf (eb_stream, "%x,", read_register (LR0_REGNUM + j + i));
fprintf (eb_stream, "%x\n", read_register (LR0_REGNUM + j + 15));
expect_prompt ();
}
fprintf (eb_stream, "s sr133,%x,%x,%x\n", read_register (BP_REGNUM),
read_register (FC_REGNUM), read_register (CR_REGNUM));
expect_prompt ();
fprintf (eb_stream, "s sr131,%x\n", read_register (Q_REGNUM));
expect_prompt ();
fprintf (eb_stream, "s sr0,");
for (i = 0; i < 11; ++i)
fprintf (eb_stream, "%x,", read_register (VAB_REGNUM + i));
fprintf (eb_stream, "%x\n", read_register (VAB_REGNUM + 11));
expect_prompt ();
}
void
eb_store_register (int regno)
{
if (regno == -1)
eb_store_registers ();
else
{
char *name = get_reg_name (regno);
fprintf (eb_stream, "s %s,%x\n", name, read_register (regno));
if (regno == GR1_REGNUM)
registers_changed ();
expect_prompt ();
}
}
void
eb_prepare_to_store (void)
{
}
int
eb_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
struct target_ops *target)
{
if (write)
return eb_write_inferior_memory (memaddr, myaddr, len);
else
return eb_read_inferior_memory (memaddr, myaddr, len);
}
void
eb_files_info (void)
{
printf ("\tAttached to %s at %d baud and running program %s.\n",
dev_name, baudrate, prog_name);
}
int
eb_write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
int i;
for (i = 0; i < len; i++)
{
if ((i % 16) == 0)
fprintf (eb_stream, "sb %x,", memaddr + i);
if ((i % 16) == 15 || i == len - 1)
{
fprintf (eb_stream, "%x\n", ((unsigned char *) myaddr)[i]);
expect_prompt ();
}
else
fprintf (eb_stream, "%x,", ((unsigned char *) myaddr)[i]);
}
return len;
}
int
eb_read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
int i;
int count;
unsigned long startaddr;
int len_this_pass;
if (((memaddr - 1) + len) < memaddr)
{
errno = EIO;
return 0;
}
startaddr = memaddr;
count = 0;
while (count < len)
{
len_this_pass = 16;
if ((startaddr % 16) != 0)
len_this_pass -= startaddr % 16;
if (len_this_pass > (len - count))
len_this_pass = (len - count);
fprintf (eb_stream, "db %x,%x\n", startaddr,
(startaddr - 1) + len_this_pass);
expect ("\n");
i = 0;
while (1)
{
if (isxdigit (readchar ()))
++i;
else
{
expect_prompt ();
error ("Hex digit expected from remote system.");
}
if (i >= 8)
break;
}
expect (" ");
for (i = 0; i < len_this_pass; i++)
get_hex_byte (&myaddr[count++]);
expect_prompt ();
startaddr += len_this_pass;
}
return len;
}
static void
eb_kill (char *args, int from_tty)
{
return;
}
void
eb_mourn_inferior (void)
{
remove_breakpoints ();
unpush_target (&eb_ops);
generic_mourn_inferior ();
}
struct target_ops eb_ops;
static void
init_eb_ops (void)
{
eb_ops.to_shortname = "amd-eb";
eb_ops.to_longname = "Remote serial AMD EBMON target";
eb_ops.to_doc = "Use a remote computer running EBMON connected by a serial line.\n\
Arguments are the name of the device for the serial line,\n\
the speed to connect at in bits per second, and the filename of the\n\
executable as it exists on the remote computer. For example,\n\
target amd-eb /dev/ttya 9600 demo",
eb_ops.to_open = eb_open;
eb_ops.to_close = eb_close;
eb_ops.to_attach = 0;
eb_ops.to_post_attach = NULL;
eb_ops.to_require_attach = NULL;
eb_ops.to_detach = eb_detach;
eb_ops.to_require_detach = NULL;
eb_ops.to_resume = eb_resume;
eb_ops.to_wait = eb_wait;
eb_ops.to_post_wait = NULL;
eb_ops.to_fetch_registers = eb_fetch_register;
eb_ops.to_store_registers = eb_store_register;
eb_ops.to_prepare_to_store = eb_prepare_to_store;
eb_ops.to_xfer_memory = eb_xfer_inferior_memory;
eb_ops.to_files_info = eb_files_info;
eb_ops.to_insert_breakpoint = 0;
eb_ops.to_remove_breakpoint = 0;
eb_ops.to_terminal_init = 0;
eb_ops.to_terminal_inferior = 0;
eb_ops.to_terminal_ours_for_output = 0;
eb_ops.to_terminal_ours = 0;
eb_ops.to_terminal_info = 0;
eb_ops.to_kill = eb_kill;
eb_ops.to_load = generic_load;
eb_ops.to_lookup_symbol = 0;
eb_ops.to_create_inferior = eb_create_inferior;
eb_ops.to_post_startup_inferior = NULL;
eb_ops.to_acknowledge_created_inferior = NULL;
eb_ops.to_clone_and_follow_inferior = NULL;
eb_ops.to_post_follow_inferior_by_clone = NULL;
eb_ops.to_insert_fork_catchpoint = NULL;
eb_ops.to_remove_fork_catchpoint = NULL;
eb_ops.to_insert_vfork_catchpoint = NULL;
eb_ops.to_remove_vfork_catchpoint = NULL;
eb_ops.to_has_forked = NULL;
eb_ops.to_has_vforked = NULL;
eb_ops.to_can_follow_vfork_prior_to_exec = NULL;
eb_ops.to_post_follow_vfork = NULL;
eb_ops.to_insert_exec_catchpoint = NULL;
eb_ops.to_remove_exec_catchpoint = NULL;
eb_ops.to_has_execd = NULL;
eb_ops.to_reported_exec_events_per_exec_call = NULL;
eb_ops.to_has_exited = NULL;
eb_ops.to_mourn_inferior = eb_mourn_inferior;
eb_ops.to_can_run = 0;
eb_ops.to_notice_signals = 0;
eb_ops.to_thread_alive = 0;
eb_ops.to_stop = 0;
eb_ops.to_pid_to_exec_file = NULL;
eb_ops.to_core_file_to_sym_file = NULL;
eb_ops.to_stratum = process_stratum;
eb_ops.DONT_USE = 0;
eb_ops.to_has_all_memory = 1;
eb_ops.to_has_memory = 1;
eb_ops.to_has_stack = 1;
eb_ops.to_has_registers = 1;
eb_ops.to_has_execution = 1;
eb_ops.to_sections = 0;
eb_ops.to_sections_end = 0;
eb_ops.to_magic = OPS_MAGIC;
};
void
_initialize_remote_eb (void)
{
init_eb_ops ();
add_target (&eb_ops);
}