xref: /openbsd-src/gnu/usr.bin/binutils/gdb/remote-st.c (revision 63addd46c1e40ca0f49488ddcdc4ab598023b0c1)
1e93f7393Sniklas /* Remote debugging interface for Tandem ST2000 phone switch, for GDB.
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000,
4b725ae77Skettenis    2001, 2002 Free Software Foundation, Inc.
5b725ae77Skettenis 
6e93f7393Sniklas    Contributed by Cygnus Support.  Written by Jim Kingdon for Cygnus.
7e93f7393Sniklas 
8e93f7393Sniklas    This file is part of GDB.
9e93f7393Sniklas 
10e93f7393Sniklas    This program is free software; you can redistribute it and/or modify
11e93f7393Sniklas    it under the terms of the GNU General Public License as published by
12e93f7393Sniklas    the Free Software Foundation; either version 2 of the License, or
13e93f7393Sniklas    (at your option) any later version.
14e93f7393Sniklas 
15e93f7393Sniklas    This program is distributed in the hope that it will be useful,
16e93f7393Sniklas    but WITHOUT ANY WARRANTY; without even the implied warranty of
17e93f7393Sniklas    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18e93f7393Sniklas    GNU General Public License for more details.
19e93f7393Sniklas 
20e93f7393Sniklas    You should have received a copy of the GNU General Public License
21e93f7393Sniklas    along with this program; if not, write to the Free Software
22b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
23b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
24e93f7393Sniklas 
25e93f7393Sniklas /* This file was derived from remote-eb.c, which did a similar job, but for
26e93f7393Sniklas    an AMD-29K running EBMON.  That file was in turn derived from remote.c
27e93f7393Sniklas    as mentioned in the following comment (left in for comic relief):
28e93f7393Sniklas 
29e93f7393Sniklas    "This is like remote.c but is for an esoteric situation--
30e93f7393Sniklas    having an a29k board in a PC hooked up to a unix machine with
31e93f7393Sniklas    a serial line, and running ctty com1 on the PC, through which
32e93f7393Sniklas    the unix machine can run ebmon.  Not to mention that the PC
33e93f7393Sniklas    has PC/NFS, so it can access the same executables that gdb can,
34e93f7393Sniklas    over the net in real time."
35e93f7393Sniklas 
36e93f7393Sniklas    In reality, this module talks to a debug monitor called 'STDEBUG', which
37e93f7393Sniklas    runs in a phone switch.  We communicate with STDEBUG via either a direct
38e93f7393Sniklas    serial line, or a TCP (or possibly TELNET) stream to a terminal multiplexor,
39e93f7393Sniklas    which in turn talks to the phone switch. */
40e93f7393Sniklas 
41e93f7393Sniklas #include "defs.h"
42e93f7393Sniklas #include "gdbcore.h"
43e93f7393Sniklas #include "target.h"
44e93f7393Sniklas #include "gdb_string.h"
45e93f7393Sniklas #include <sys/types.h>
46e93f7393Sniklas #include "serial.h"
47b725ae77Skettenis #include "regcache.h"
48e93f7393Sniklas 
49e93f7393Sniklas extern struct target_ops st2000_ops;	/* Forward declaration */
50e93f7393Sniklas 
51e93f7393Sniklas static void st2000_close ();
52e93f7393Sniklas static void st2000_fetch_register ();
53e93f7393Sniklas static void st2000_store_register ();
54e93f7393Sniklas 
55e93f7393Sniklas #define LOG_FILE "st2000.log"
56e93f7393Sniklas #if defined (LOG_FILE)
57e93f7393Sniklas FILE *log_file;
58e93f7393Sniklas #endif
59e93f7393Sniklas 
60e93f7393Sniklas static int timeout = 24;
61e93f7393Sniklas 
62e93f7393Sniklas /* Descriptor for I/O to remote machine.  Initialize it to -1 so that
63e93f7393Sniklas    st2000_open knows that we don't have a file open when the program
64e93f7393Sniklas    starts.  */
65e93f7393Sniklas 
66b725ae77Skettenis static struct serial *st2000_desc;
67e93f7393Sniklas 
68e93f7393Sniklas /* Send data to stdebug.  Works just like printf. */
69e93f7393Sniklas 
70e93f7393Sniklas static void
printf_stdebug(char * pattern,...)71e93f7393Sniklas printf_stdebug (char *pattern,...)
72e93f7393Sniklas {
73e93f7393Sniklas   va_list args;
74e93f7393Sniklas   char buf[200];
75e93f7393Sniklas 
76e93f7393Sniklas   va_start (args, pattern);
77e93f7393Sniklas 
78e93f7393Sniklas   vsprintf (buf, pattern, args);
79e93f7393Sniklas   va_end (args);
80e93f7393Sniklas 
81b725ae77Skettenis   if (serial_write (st2000_desc, buf, strlen (buf)))
82b725ae77Skettenis     fprintf_unfiltered (gdb_stderr, "serial_write failed: %s\n",
83b725ae77Skettenis 			safe_strerror (errno));
84e93f7393Sniklas }
85e93f7393Sniklas 
86e93f7393Sniklas /* Read a character from the remote system, doing all the fancy timeout
87e93f7393Sniklas    stuff.  */
88e93f7393Sniklas 
89e93f7393Sniklas static int
readchar(int timeout)90b725ae77Skettenis readchar (int timeout)
91e93f7393Sniklas {
92e93f7393Sniklas   int c;
93e93f7393Sniklas 
94b725ae77Skettenis   c = serial_readchar (st2000_desc, timeout);
95e93f7393Sniklas 
96e93f7393Sniklas #ifdef LOG_FILE
97e93f7393Sniklas   putc (c & 0x7f, log_file);
98e93f7393Sniklas #endif
99e93f7393Sniklas 
100e93f7393Sniklas   if (c >= 0)
101e93f7393Sniklas     return c & 0x7f;
102e93f7393Sniklas 
103e93f7393Sniklas   if (c == SERIAL_TIMEOUT)
104e93f7393Sniklas     {
105e93f7393Sniklas       if (timeout == 0)
106e93f7393Sniklas 	return c;		/* Polls shouldn't generate timeout errors */
107e93f7393Sniklas 
108e93f7393Sniklas       error ("Timeout reading from remote system.");
109e93f7393Sniklas     }
110e93f7393Sniklas 
111e93f7393Sniklas   perror_with_name ("remote-st2000");
112e93f7393Sniklas }
113e93f7393Sniklas 
114e93f7393Sniklas /* Scan input from the remote system, until STRING is found.  If DISCARD is
115e93f7393Sniklas    non-zero, then discard non-matching input, else print it out.
116e93f7393Sniklas    Let the user break out immediately.  */
117e93f7393Sniklas static void
expect(char * string,int discard)118b725ae77Skettenis expect (char *string, int discard)
119e93f7393Sniklas {
120e93f7393Sniklas   char *p = string;
121e93f7393Sniklas   int c;
122e93f7393Sniklas 
123b725ae77Skettenis   immediate_quit++;
124e93f7393Sniklas   while (1)
125e93f7393Sniklas     {
126e93f7393Sniklas       c = readchar (timeout);
127e93f7393Sniklas       if (c == *p++)
128e93f7393Sniklas 	{
129e93f7393Sniklas 	  if (*p == '\0')
130e93f7393Sniklas 	    {
131b725ae77Skettenis 	      immediate_quit--;
132e93f7393Sniklas 	      return;
133e93f7393Sniklas 	    }
134e93f7393Sniklas 	}
135e93f7393Sniklas       else
136e93f7393Sniklas 	{
137e93f7393Sniklas 	  if (!discard)
138e93f7393Sniklas 	    {
139e93f7393Sniklas 	      fwrite (string, 1, (p - 1) - string, stdout);
140e93f7393Sniklas 	      putchar ((char) c);
141e93f7393Sniklas 	      fflush (stdout);
142e93f7393Sniklas 	    }
143e93f7393Sniklas 	  p = string;
144e93f7393Sniklas 	}
145e93f7393Sniklas     }
146e93f7393Sniklas }
147e93f7393Sniklas 
148e93f7393Sniklas /* Keep discarding input until we see the STDEBUG prompt.
149e93f7393Sniklas 
150e93f7393Sniklas    The convention for dealing with the prompt is that you
151e93f7393Sniklas    o give your command
152e93f7393Sniklas    o *then* wait for the prompt.
153e93f7393Sniklas 
154e93f7393Sniklas    Thus the last thing that a procedure does with the serial line
155e93f7393Sniklas    will be an expect_prompt().  Exception:  st2000_resume does not
156e93f7393Sniklas    wait for the prompt, because the terminal is being handed over
157e93f7393Sniklas    to the inferior.  However, the next thing which happens after that
158e93f7393Sniklas    is a st2000_wait which does wait for the prompt.
159e93f7393Sniklas    Note that this includes abnormal exit, e.g. error().  This is
160e93f7393Sniklas    necessary to prevent getting into states from which we can't
161e93f7393Sniklas    recover.  */
162e93f7393Sniklas static void
expect_prompt(int discard)163b725ae77Skettenis expect_prompt (int discard)
164e93f7393Sniklas {
165e93f7393Sniklas #if defined (LOG_FILE)
166e93f7393Sniklas   /* This is a convenient place to do this.  The idea is to do it often
167e93f7393Sniklas      enough that we never lose much data if we terminate abnormally.  */
168e93f7393Sniklas   fflush (log_file);
169e93f7393Sniklas #endif
170e93f7393Sniklas   expect ("dbug> ", discard);
171e93f7393Sniklas }
172e93f7393Sniklas 
173e93f7393Sniklas /* Get a hex digit from the remote system & return its value.
174e93f7393Sniklas    If ignore_space is nonzero, ignore spaces (not newline, tab, etc).  */
175e93f7393Sniklas static int
get_hex_digit(int ignore_space)176b725ae77Skettenis get_hex_digit (int ignore_space)
177e93f7393Sniklas {
178e93f7393Sniklas   int ch;
179e93f7393Sniklas   while (1)
180e93f7393Sniklas     {
181e93f7393Sniklas       ch = readchar (timeout);
182e93f7393Sniklas       if (ch >= '0' && ch <= '9')
183e93f7393Sniklas 	return ch - '0';
184e93f7393Sniklas       else if (ch >= 'A' && ch <= 'F')
185e93f7393Sniklas 	return ch - 'A' + 10;
186e93f7393Sniklas       else if (ch >= 'a' && ch <= 'f')
187e93f7393Sniklas 	return ch - 'a' + 10;
188e93f7393Sniklas       else if (ch == ' ' && ignore_space)
189e93f7393Sniklas 	;
190e93f7393Sniklas       else
191e93f7393Sniklas 	{
192e93f7393Sniklas 	  expect_prompt (1);
193e93f7393Sniklas 	  error ("Invalid hex digit from remote system.");
194e93f7393Sniklas 	}
195e93f7393Sniklas     }
196e93f7393Sniklas }
197e93f7393Sniklas 
198e93f7393Sniklas /* Get a byte from stdebug and put it in *BYT.  Accept any number
199e93f7393Sniklas    leading spaces.  */
200e93f7393Sniklas static void
get_hex_byte(char * byt)201b725ae77Skettenis get_hex_byte (char *byt)
202e93f7393Sniklas {
203e93f7393Sniklas   int val;
204e93f7393Sniklas 
205e93f7393Sniklas   val = get_hex_digit (1) << 4;
206e93f7393Sniklas   val |= get_hex_digit (0);
207e93f7393Sniklas   *byt = val;
208e93f7393Sniklas }
209e93f7393Sniklas 
210e93f7393Sniklas /* Get N 32-bit words from remote, each preceded by a space,
211e93f7393Sniklas    and put them in registers starting at REGNO.  */
212e93f7393Sniklas static void
get_hex_regs(int n,int regno)213b725ae77Skettenis get_hex_regs (int n, int regno)
214e93f7393Sniklas {
215e93f7393Sniklas   long val;
216e93f7393Sniklas   int i;
217e93f7393Sniklas 
218e93f7393Sniklas   for (i = 0; i < n; i++)
219e93f7393Sniklas     {
220e93f7393Sniklas       int j;
221e93f7393Sniklas 
222e93f7393Sniklas       val = 0;
223e93f7393Sniklas       for (j = 0; j < 8; j++)
224e93f7393Sniklas 	val = (val << 4) + get_hex_digit (j == 0);
225*63addd46Skettenis       regcache_raw_supply (current_regcache, regno++, (char *) &val);
226e93f7393Sniklas     }
227e93f7393Sniklas }
228e93f7393Sniklas 
229e93f7393Sniklas /* This is called not only when we first attach, but also when the
230e93f7393Sniklas    user types "run" after having attached.  */
231e93f7393Sniklas static void
st2000_create_inferior(char * execfile,char * args,char ** env,int from_tty)232*63addd46Skettenis st2000_create_inferior (char *execfile, char *args, char **env,
233*63addd46Skettenis 			int from_tty)
234e93f7393Sniklas {
235e93f7393Sniklas   int entry_pt;
236e93f7393Sniklas 
237e93f7393Sniklas   if (args && *args)
238e93f7393Sniklas     error ("Can't pass arguments to remote STDEBUG process");
239e93f7393Sniklas 
240e93f7393Sniklas   if (execfile == 0 || exec_bfd == 0)
241b725ae77Skettenis     error ("No executable file specified");
242e93f7393Sniklas 
243e93f7393Sniklas   entry_pt = (int) bfd_get_start_address (exec_bfd);
244e93f7393Sniklas 
245e93f7393Sniklas /* The "process" (board) is already stopped awaiting our commands, and
246e93f7393Sniklas    the program is already downloaded.  We just set its PC and go.  */
247e93f7393Sniklas 
248e93f7393Sniklas   clear_proceed_status ();
249e93f7393Sniklas 
250e93f7393Sniklas   /* Tell wait_for_inferior that we've started a new process.  */
251e93f7393Sniklas   init_wait_for_inferior ();
252e93f7393Sniklas 
253e93f7393Sniklas   /* Set up the "saved terminal modes" of the inferior
254e93f7393Sniklas      based on what modes we are starting it with.  */
255e93f7393Sniklas   target_terminal_init ();
256e93f7393Sniklas 
257e93f7393Sniklas   /* Install inferior's terminal modes.  */
258e93f7393Sniklas   target_terminal_inferior ();
259e93f7393Sniklas 
260e93f7393Sniklas   /* insert_step_breakpoint ();  FIXME, do we need this?  */
261e93f7393Sniklas   /* Let 'er rip... */
262e93f7393Sniklas   proceed ((CORE_ADDR) entry_pt, TARGET_SIGNAL_DEFAULT, 0);
263e93f7393Sniklas }
264e93f7393Sniklas 
265e93f7393Sniklas /* Open a connection to a remote debugger.
266e93f7393Sniklas    NAME is the filename used for communication.  */
267e93f7393Sniklas 
268e93f7393Sniklas static int baudrate = 9600;
269e93f7393Sniklas static char dev_name[100];
270e93f7393Sniklas 
271e93f7393Sniklas static void
st2000_open(char * args,int from_tty)272b725ae77Skettenis st2000_open (char *args, int from_tty)
273e93f7393Sniklas {
274e93f7393Sniklas   int n;
275e93f7393Sniklas   char junk[100];
276e93f7393Sniklas 
277e93f7393Sniklas   target_preopen (from_tty);
278e93f7393Sniklas 
279e93f7393Sniklas   n = sscanf (args, " %s %d %s", dev_name, &baudrate, junk);
280e93f7393Sniklas 
281e93f7393Sniklas   if (n != 2)
282e93f7393Sniklas     error ("Bad arguments.  Usage: target st2000 <device> <speed>\n\
283e93f7393Sniklas or target st2000 <host> <port>\n");
284e93f7393Sniklas 
285e93f7393Sniklas   st2000_close (0);
286e93f7393Sniklas 
287b725ae77Skettenis   st2000_desc = serial_open (dev_name);
288e93f7393Sniklas 
289e93f7393Sniklas   if (!st2000_desc)
290e93f7393Sniklas     perror_with_name (dev_name);
291e93f7393Sniklas 
292b725ae77Skettenis   if (serial_setbaudrate (st2000_desc, baudrate))
293b725ae77Skettenis     {
294b725ae77Skettenis       serial_close (dev_name);
295b725ae77Skettenis       perror_with_name (dev_name);
296b725ae77Skettenis     }
297e93f7393Sniklas 
298b725ae77Skettenis   serial_raw (st2000_desc);
299e93f7393Sniklas 
300e93f7393Sniklas   push_target (&st2000_ops);
301e93f7393Sniklas 
302e93f7393Sniklas #if defined (LOG_FILE)
303e93f7393Sniklas   log_file = fopen (LOG_FILE, "w");
304e93f7393Sniklas   if (log_file == NULL)
305e93f7393Sniklas     perror_with_name (LOG_FILE);
306e93f7393Sniklas #endif
307e93f7393Sniklas 
308e93f7393Sniklas   /* Hello?  Are you there?  */
309e93f7393Sniklas   printf_stdebug ("\003");	/* ^C wakes up dbug */
310e93f7393Sniklas 
311e93f7393Sniklas   expect_prompt (1);
312e93f7393Sniklas 
313e93f7393Sniklas   if (from_tty)
314e93f7393Sniklas     printf ("Remote %s connected to %s\n", target_shortname,
315e93f7393Sniklas 	    dev_name);
316e93f7393Sniklas }
317e93f7393Sniklas 
318e93f7393Sniklas /* Close out all files and local state before this target loses control. */
319e93f7393Sniklas 
320e93f7393Sniklas static void
st2000_close(int quitting)321b725ae77Skettenis st2000_close (int quitting)
322e93f7393Sniklas {
323b725ae77Skettenis   serial_close (st2000_desc);
324e93f7393Sniklas 
325e93f7393Sniklas #if defined (LOG_FILE)
326b725ae77Skettenis   if (log_file)
327b725ae77Skettenis     {
328e93f7393Sniklas       if (ferror (log_file))
329b725ae77Skettenis 	fprintf_unfiltered (gdb_stderr, "Error writing log file.\n");
330e93f7393Sniklas       if (fclose (log_file) != 0)
331b725ae77Skettenis 	fprintf_unfiltered (gdb_stderr, "Error closing log file.\n");
332e93f7393Sniklas     }
333e93f7393Sniklas #endif
334e93f7393Sniklas }
335e93f7393Sniklas 
336e93f7393Sniklas /* Terminate the open connection to the remote debugger.
337e93f7393Sniklas    Use this when you want to detach and do something else
338e93f7393Sniklas    with your gdb.  */
339e93f7393Sniklas static void
st2000_detach(int from_tty)340b725ae77Skettenis st2000_detach (int from_tty)
341e93f7393Sniklas {
342e93f7393Sniklas   pop_target ();		/* calls st2000_close to do the real work */
343e93f7393Sniklas   if (from_tty)
344e93f7393Sniklas     printf ("Ending remote %s debugging\n", target_shortname);
345e93f7393Sniklas }
346e93f7393Sniklas 
347e93f7393Sniklas /* Tell the remote machine to resume.  */
348e93f7393Sniklas 
349e93f7393Sniklas static void
st2000_resume(ptid_t ptid,int step,enum target_signal sig)350b725ae77Skettenis st2000_resume (ptid_t ptid, int step, enum target_signal sig)
351e93f7393Sniklas {
352e93f7393Sniklas   if (step)
353e93f7393Sniklas     {
354e93f7393Sniklas       printf_stdebug ("ST\r");
355e93f7393Sniklas       /* Wait for the echo.  */
356e93f7393Sniklas       expect ("ST\r", 1);
357e93f7393Sniklas     }
358e93f7393Sniklas   else
359e93f7393Sniklas     {
360e93f7393Sniklas       printf_stdebug ("GO\r");
361e93f7393Sniklas       /* Swallow the echo.  */
362e93f7393Sniklas       expect ("GO\r", 1);
363e93f7393Sniklas     }
364e93f7393Sniklas }
365e93f7393Sniklas 
366e93f7393Sniklas /* Wait until the remote machine stops, then return,
367e93f7393Sniklas    storing status in STATUS just as `wait' would.  */
368e93f7393Sniklas 
369b725ae77Skettenis static ptid_t
st2000_wait(ptid_t ptid,struct target_waitstatus * status)370b725ae77Skettenis st2000_wait (ptid_t ptid, struct target_waitstatus *status)
371e93f7393Sniklas {
372e93f7393Sniklas   int old_timeout = timeout;
373e93f7393Sniklas 
374e93f7393Sniklas   status->kind = TARGET_WAITKIND_EXITED;
375e93f7393Sniklas   status->value.integer = 0;
376e93f7393Sniklas 
377e93f7393Sniklas   timeout = 0;			/* Don't time out -- user program is running. */
378e93f7393Sniklas 
379e93f7393Sniklas   expect_prompt (0);		/* Wait for prompt, outputting extraneous text */
380e93f7393Sniklas 
381e93f7393Sniklas   status->kind = TARGET_WAITKIND_STOPPED;
382e93f7393Sniklas   status->value.sig = TARGET_SIGNAL_TRAP;
383e93f7393Sniklas 
384e93f7393Sniklas   timeout = old_timeout;
385e93f7393Sniklas 
386b725ae77Skettenis   return inferior_ptid;
387e93f7393Sniklas }
388e93f7393Sniklas 
389b725ae77Skettenis /* Return the name of register number REGNO in the form input and
390b725ae77Skettenis    output by STDEBUG.  Currently, REGISTER_NAME just happens return
391b725ae77Skettenis    exactly what STDEBUG wants.  Lets take advantage of that just as
392b725ae77Skettenis    long as possible! */
393e93f7393Sniklas 
394e93f7393Sniklas static char *
get_reg_name(int regno)395b725ae77Skettenis get_reg_name (int regno)
396e93f7393Sniklas {
397e93f7393Sniklas   static char buf[50];
398e93f7393Sniklas   const char *p;
399e93f7393Sniklas   char *b;
400e93f7393Sniklas 
401e93f7393Sniklas   b = buf;
402e93f7393Sniklas 
403b725ae77Skettenis   for (p = REGISTER_NAME (regno); *p; p++)
404e93f7393Sniklas     *b++ = toupper (*p);
405e93f7393Sniklas   *b = '\000';
406e93f7393Sniklas 
407e93f7393Sniklas   return buf;
408e93f7393Sniklas }
409e93f7393Sniklas 
410e93f7393Sniklas /* Read the remote registers into the block REGS.  */
411e93f7393Sniklas 
412e93f7393Sniklas static void
st2000_fetch_registers(void)413b725ae77Skettenis st2000_fetch_registers (void)
414e93f7393Sniklas {
415e93f7393Sniklas   int regno;
416e93f7393Sniklas 
417e93f7393Sniklas   /* Yeah yeah, I know this is horribly inefficient.  But it isn't done
418e93f7393Sniklas      very often...  I'll clean it up later.  */
419e93f7393Sniklas 
420e93f7393Sniklas   for (regno = 0; regno <= PC_REGNUM; regno++)
421e93f7393Sniklas     st2000_fetch_register (regno);
422e93f7393Sniklas }
423e93f7393Sniklas 
424e93f7393Sniklas /* Fetch register REGNO, or all registers if REGNO is -1.
425e93f7393Sniklas    Returns errno value.  */
426e93f7393Sniklas static void
st2000_fetch_register(int regno)427b725ae77Skettenis st2000_fetch_register (int regno)
428e93f7393Sniklas {
429e93f7393Sniklas   if (regno == -1)
430e93f7393Sniklas     st2000_fetch_registers ();
431e93f7393Sniklas   else
432e93f7393Sniklas     {
433e93f7393Sniklas       char *name = get_reg_name (regno);
434e93f7393Sniklas       printf_stdebug ("DR %s\r", name);
435e93f7393Sniklas       expect (name, 1);
436e93f7393Sniklas       expect (" : ", 1);
437e93f7393Sniklas       get_hex_regs (1, regno);
438e93f7393Sniklas       expect_prompt (1);
439e93f7393Sniklas     }
440e93f7393Sniklas   return;
441e93f7393Sniklas }
442e93f7393Sniklas 
443e93f7393Sniklas /* Store the remote registers from the contents of the block REGS.  */
444e93f7393Sniklas 
445e93f7393Sniklas static void
st2000_store_registers(void)446b725ae77Skettenis st2000_store_registers (void)
447e93f7393Sniklas {
448e93f7393Sniklas   int regno;
449e93f7393Sniklas 
450e93f7393Sniklas   for (regno = 0; regno <= PC_REGNUM; regno++)
451e93f7393Sniklas     st2000_store_register (regno);
452e93f7393Sniklas 
453e93f7393Sniklas   registers_changed ();
454e93f7393Sniklas }
455e93f7393Sniklas 
456e93f7393Sniklas /* Store register REGNO, or all if REGNO == 0.
457e93f7393Sniklas    Return errno value.  */
458e93f7393Sniklas static void
st2000_store_register(int regno)459b725ae77Skettenis st2000_store_register (int regno)
460e93f7393Sniklas {
461e93f7393Sniklas   if (regno == -1)
462e93f7393Sniklas     st2000_store_registers ();
463e93f7393Sniklas   else
464e93f7393Sniklas     {
465e93f7393Sniklas       printf_stdebug ("PR %s %x\r", get_reg_name (regno),
466e93f7393Sniklas 		      read_register (regno));
467e93f7393Sniklas 
468e93f7393Sniklas       expect_prompt (1);
469e93f7393Sniklas     }
470e93f7393Sniklas }
471e93f7393Sniklas 
472e93f7393Sniklas /* Get ready to modify the registers array.  On machines which store
473e93f7393Sniklas    individual registers, this doesn't need to do anything.  On machines
474e93f7393Sniklas    which store all the registers in one fell swoop, this makes sure
475e93f7393Sniklas    that registers contains all the registers from the program being
476e93f7393Sniklas    debugged.  */
477e93f7393Sniklas 
478e93f7393Sniklas static void
st2000_prepare_to_store(void)479b725ae77Skettenis st2000_prepare_to_store (void)
480e93f7393Sniklas {
481e93f7393Sniklas   /* Do nothing, since we can store individual regs */
482e93f7393Sniklas }
483e93f7393Sniklas 
484e93f7393Sniklas static void
st2000_files_info(void)485b725ae77Skettenis st2000_files_info (void)
486e93f7393Sniklas {
487e93f7393Sniklas   printf ("\tAttached to %s at %d baud.\n",
488e93f7393Sniklas 	  dev_name, baudrate);
489e93f7393Sniklas }
490e93f7393Sniklas 
491e93f7393Sniklas /* Copy LEN bytes of data from debugger memory at MYADDR
492e93f7393Sniklas    to inferior's memory at MEMADDR.  Returns length moved.  */
493e93f7393Sniklas static int
st2000_write_inferior_memory(CORE_ADDR memaddr,unsigned char * myaddr,int len)494b725ae77Skettenis st2000_write_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
495e93f7393Sniklas {
496e93f7393Sniklas   int i;
497e93f7393Sniklas 
498e93f7393Sniklas   for (i = 0; i < len; i++)
499e93f7393Sniklas     {
500e93f7393Sniklas       printf_stdebug ("PM.B %x %x\r", memaddr + i, myaddr[i]);
501e93f7393Sniklas       expect_prompt (1);
502e93f7393Sniklas     }
503e93f7393Sniklas   return len;
504e93f7393Sniklas }
505e93f7393Sniklas 
506e93f7393Sniklas /* Read LEN bytes from inferior memory at MEMADDR.  Put the result
507e93f7393Sniklas    at debugger address MYADDR.  Returns length moved.  */
508e93f7393Sniklas static int
st2000_read_inferior_memory(CORE_ADDR memaddr,char * myaddr,int len)509b725ae77Skettenis st2000_read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
510e93f7393Sniklas {
511e93f7393Sniklas   int i;
512e93f7393Sniklas 
513e93f7393Sniklas   /* Number of bytes read so far.  */
514e93f7393Sniklas   int count;
515e93f7393Sniklas 
516e93f7393Sniklas   /* Starting address of this pass.  */
517e93f7393Sniklas   unsigned long startaddr;
518e93f7393Sniklas 
519e93f7393Sniklas   /* Number of bytes to read in this pass.  */
520e93f7393Sniklas   int len_this_pass;
521e93f7393Sniklas 
522e93f7393Sniklas   /* Note that this code works correctly if startaddr is just less
523e93f7393Sniklas      than UINT_MAX (well, really CORE_ADDR_MAX if there was such a
524e93f7393Sniklas      thing).  That is, something like
525e93f7393Sniklas      st2000_read_bytes (CORE_ADDR_MAX - 4, foo, 4)
526e93f7393Sniklas      works--it never adds len to memaddr and gets 0.  */
527e93f7393Sniklas   /* However, something like
528e93f7393Sniklas      st2000_read_bytes (CORE_ADDR_MAX - 3, foo, 4)
529e93f7393Sniklas      doesn't need to work.  Detect it and give up if there's an attempt
530e93f7393Sniklas      to do that.  */
531b725ae77Skettenis   if (((memaddr - 1) + len) < memaddr)
532b725ae77Skettenis     {
533e93f7393Sniklas       errno = EIO;
534e93f7393Sniklas       return 0;
535e93f7393Sniklas     }
536e93f7393Sniklas 
537e93f7393Sniklas   startaddr = memaddr;
538e93f7393Sniklas   count = 0;
539e93f7393Sniklas   while (count < len)
540e93f7393Sniklas     {
541e93f7393Sniklas       len_this_pass = 16;
542e93f7393Sniklas       if ((startaddr % 16) != 0)
543e93f7393Sniklas 	len_this_pass -= startaddr % 16;
544e93f7393Sniklas       if (len_this_pass > (len - count))
545e93f7393Sniklas 	len_this_pass = (len - count);
546e93f7393Sniklas 
547e93f7393Sniklas       printf_stdebug ("DI.L %x %x\r", startaddr, len_this_pass);
548e93f7393Sniklas       expect (":  ", 1);
549e93f7393Sniklas 
550e93f7393Sniklas       for (i = 0; i < len_this_pass; i++)
551e93f7393Sniklas 	get_hex_byte (&myaddr[count++]);
552e93f7393Sniklas 
553e93f7393Sniklas       expect_prompt (1);
554e93f7393Sniklas 
555e93f7393Sniklas       startaddr += len_this_pass;
556e93f7393Sniklas     }
557e93f7393Sniklas   return len;
558e93f7393Sniklas }
559e93f7393Sniklas 
560b725ae77Skettenis /* Transfer LEN bytes between GDB address MYADDR and target address
561b725ae77Skettenis    MEMADDR.  If WRITE is non-zero, transfer them to the target,
562b725ae77Skettenis    otherwise transfer them from the target.  TARGET is unused.
563b725ae77Skettenis 
564b725ae77Skettenis    Returns the number of bytes transferred. */
565b725ae77Skettenis 
566e93f7393Sniklas static int
st2000_xfer_inferior_memory(CORE_ADDR memaddr,char * myaddr,int len,int write,struct mem_attrib * attrib,struct target_ops * target)567b725ae77Skettenis st2000_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
568b725ae77Skettenis 			     int write, struct mem_attrib *attrib,
569b725ae77Skettenis 			     struct target_ops *target)
570e93f7393Sniklas {
571e93f7393Sniklas   if (write)
572e93f7393Sniklas     return st2000_write_inferior_memory (memaddr, myaddr, len);
573e93f7393Sniklas   else
574e93f7393Sniklas     return st2000_read_inferior_memory (memaddr, myaddr, len);
575e93f7393Sniklas }
576e93f7393Sniklas 
577e93f7393Sniklas static void
st2000_kill(char * args,int from_tty)578b725ae77Skettenis st2000_kill (char *args, int from_tty)
579e93f7393Sniklas {
580e93f7393Sniklas   return;			/* Ignore attempts to kill target system */
581e93f7393Sniklas }
582e93f7393Sniklas 
583e93f7393Sniklas /* Clean up when a program exits.
584e93f7393Sniklas 
585e93f7393Sniklas    The program actually lives on in the remote processor's RAM, and may be
586e93f7393Sniklas    run again without a download.  Don't leave it full of breakpoint
587e93f7393Sniklas    instructions.  */
588e93f7393Sniklas 
589e93f7393Sniklas static void
st2000_mourn_inferior(void)590b725ae77Skettenis st2000_mourn_inferior (void)
591e93f7393Sniklas {
592e93f7393Sniklas   remove_breakpoints ();
593e93f7393Sniklas   unpush_target (&st2000_ops);
594e93f7393Sniklas   generic_mourn_inferior ();	/* Do all the proper things now */
595e93f7393Sniklas }
596e93f7393Sniklas 
597e93f7393Sniklas #define MAX_STDEBUG_BREAKPOINTS 16
598e93f7393Sniklas 
599b725ae77Skettenis static CORE_ADDR breakaddr[MAX_STDEBUG_BREAKPOINTS] =
600b725ae77Skettenis {0};
601e93f7393Sniklas 
602e93f7393Sniklas static int
st2000_insert_breakpoint(CORE_ADDR addr,char * shadow)603b725ae77Skettenis st2000_insert_breakpoint (CORE_ADDR addr, char *shadow)
604e93f7393Sniklas {
605e93f7393Sniklas   int i;
606b725ae77Skettenis   CORE_ADDR bp_addr = addr;
607b725ae77Skettenis   int bp_size = 0;
608b725ae77Skettenis 
609b725ae77Skettenis   BREAKPOINT_FROM_PC (&bp_addr, &bp_size);
610e93f7393Sniklas 
611e93f7393Sniklas   for (i = 0; i <= MAX_STDEBUG_BREAKPOINTS; i++)
612e93f7393Sniklas     if (breakaddr[i] == 0)
613e93f7393Sniklas       {
614e93f7393Sniklas 	breakaddr[i] = addr;
615e93f7393Sniklas 
616b725ae77Skettenis 	st2000_read_inferior_memory (bp_addr, shadow, bp_size);
617e93f7393Sniklas 	printf_stdebug ("BR %x H\r", addr);
618e93f7393Sniklas 	expect_prompt (1);
619e93f7393Sniklas 	return 0;
620e93f7393Sniklas       }
621e93f7393Sniklas 
622b725ae77Skettenis   fprintf_unfiltered (gdb_stderr, "Too many breakpoints (> 16) for STDBUG\n");
623e93f7393Sniklas   return 1;
624e93f7393Sniklas }
625e93f7393Sniklas 
626e93f7393Sniklas static int
st2000_remove_breakpoint(CORE_ADDR addr,char * shadow)627b725ae77Skettenis st2000_remove_breakpoint (CORE_ADDR addr, char *shadow)
628e93f7393Sniklas {
629e93f7393Sniklas   int i;
630e93f7393Sniklas 
631e93f7393Sniklas   for (i = 0; i < MAX_STDEBUG_BREAKPOINTS; i++)
632e93f7393Sniklas     if (breakaddr[i] == addr)
633e93f7393Sniklas       {
634e93f7393Sniklas 	breakaddr[i] = 0;
635e93f7393Sniklas 
636e93f7393Sniklas 	printf_stdebug ("CB %d\r", i);
637e93f7393Sniklas 	expect_prompt (1);
638e93f7393Sniklas 	return 0;
639e93f7393Sniklas       }
640e93f7393Sniklas 
641b725ae77Skettenis   fprintf_unfiltered (gdb_stderr,
642b725ae77Skettenis 		      "Can't find breakpoint associated with 0x%x\n", addr);
643e93f7393Sniklas   return 1;
644e93f7393Sniklas }
645e93f7393Sniklas 
646e93f7393Sniklas 
647e93f7393Sniklas /* Put a command string, in args, out to STDBUG.  Output from STDBUG is placed
648e93f7393Sniklas    on the users terminal until the prompt is seen. */
649e93f7393Sniklas 
650e93f7393Sniklas static void
st2000_command(char * args,int fromtty)651b725ae77Skettenis st2000_command (char *args, int fromtty)
652e93f7393Sniklas {
653e93f7393Sniklas   if (!st2000_desc)
654e93f7393Sniklas     error ("st2000 target not open.");
655e93f7393Sniklas 
656e93f7393Sniklas   if (!args)
657e93f7393Sniklas     error ("Missing command.");
658e93f7393Sniklas 
659e93f7393Sniklas   printf_stdebug ("%s\r", args);
660e93f7393Sniklas   expect_prompt (0);
661e93f7393Sniklas }
662e93f7393Sniklas 
663e93f7393Sniklas /* Connect the user directly to STDBUG.  This command acts just like the
664e93f7393Sniklas    'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
665e93f7393Sniklas 
666e93f7393Sniklas /*static struct ttystate ttystate; */
667e93f7393Sniklas 
668e93f7393Sniklas static void
cleanup_tty(void)669b725ae77Skettenis cleanup_tty (void)
670e93f7393Sniklas {
671e93f7393Sniklas   printf ("\r\n[Exiting connect mode]\r\n");
672b725ae77Skettenis /*  serial_restore(0, &ttystate); */
673e93f7393Sniklas }
674e93f7393Sniklas 
675e93f7393Sniklas #if 0
676e93f7393Sniklas /* This all should now be in serial.c */
677e93f7393Sniklas 
678e93f7393Sniklas static void
679b725ae77Skettenis connect_command (char *args, int fromtty)
680e93f7393Sniklas {
681e93f7393Sniklas   fd_set readfds;
682e93f7393Sniklas   int numfds;
683e93f7393Sniklas   int c;
684e93f7393Sniklas   char cur_esc = 0;
685e93f7393Sniklas 
686e93f7393Sniklas   dont_repeat ();
687e93f7393Sniklas 
688e93f7393Sniklas   if (st2000_desc < 0)
689e93f7393Sniklas     error ("st2000 target not open.");
690e93f7393Sniklas 
691e93f7393Sniklas   if (args)
692e93f7393Sniklas     fprintf ("This command takes no args.  They have been ignored.\n");
693e93f7393Sniklas 
694e93f7393Sniklas   printf ("[Entering connect mode.  Use ~. or ~^D to escape]\n");
695e93f7393Sniklas 
696e93f7393Sniklas   serial_raw (0, &ttystate);
697e93f7393Sniklas 
698e93f7393Sniklas   make_cleanup (cleanup_tty, 0);
699e93f7393Sniklas 
700e93f7393Sniklas   FD_ZERO (&readfds);
701e93f7393Sniklas 
702e93f7393Sniklas   while (1)
703e93f7393Sniklas     {
704e93f7393Sniklas       do
705e93f7393Sniklas 	{
706e93f7393Sniklas 	  FD_SET (0, &readfds);
707b725ae77Skettenis 	  FD_SET (deprecated_serial_fd (st2000_desc), &readfds);
708e93f7393Sniklas 	  numfds = select (sizeof (readfds) * 8, &readfds, 0, 0, 0);
709e93f7393Sniklas 	}
710e93f7393Sniklas       while (numfds == 0);
711e93f7393Sniklas 
712e93f7393Sniklas       if (numfds < 0)
713e93f7393Sniklas 	perror_with_name ("select");
714e93f7393Sniklas 
715e93f7393Sniklas       if (FD_ISSET (0, &readfds))
716e93f7393Sniklas 	{			/* tty input, send to stdebug */
717e93f7393Sniklas 	  c = getchar ();
718e93f7393Sniklas 	  if (c < 0)
719e93f7393Sniklas 	    perror_with_name ("connect");
720e93f7393Sniklas 
721e93f7393Sniklas 	  printf_stdebug ("%c", c);
722e93f7393Sniklas 	  switch (cur_esc)
723e93f7393Sniklas 	    {
724e93f7393Sniklas 	    case 0:
725e93f7393Sniklas 	      if (c == '\r')
726e93f7393Sniklas 		cur_esc = c;
727e93f7393Sniklas 	      break;
728e93f7393Sniklas 	    case '\r':
729e93f7393Sniklas 	      if (c == '~')
730e93f7393Sniklas 		cur_esc = c;
731e93f7393Sniklas 	      else
732e93f7393Sniklas 		cur_esc = 0;
733e93f7393Sniklas 	      break;
734e93f7393Sniklas 	    case '~':
735e93f7393Sniklas 	      if (c == '.' || c == '\004')
736e93f7393Sniklas 		return;
737e93f7393Sniklas 	      else
738e93f7393Sniklas 		cur_esc = 0;
739e93f7393Sniklas 	    }
740e93f7393Sniklas 	}
741e93f7393Sniklas 
742b725ae77Skettenis       if (FD_ISSET (deprecated_serial_fd (st2000_desc), &readfds))
743e93f7393Sniklas 	{
744e93f7393Sniklas 	  while (1)
745e93f7393Sniklas 	    {
746e93f7393Sniklas 	      c = readchar (0);
747e93f7393Sniklas 	      if (c < 0)
748e93f7393Sniklas 		break;
749e93f7393Sniklas 	      putchar (c);
750e93f7393Sniklas 	    }
751e93f7393Sniklas 	  fflush (stdout);
752e93f7393Sniklas 	}
753e93f7393Sniklas     }
754e93f7393Sniklas }
755e93f7393Sniklas #endif /* 0 */
756e93f7393Sniklas 
757e93f7393Sniklas /* Define the target subroutine names */
758e93f7393Sniklas 
759b725ae77Skettenis struct target_ops st2000_ops;
760b725ae77Skettenis 
761b725ae77Skettenis static void
init_st2000_ops(void)762b725ae77Skettenis init_st2000_ops (void)
763b725ae77Skettenis {
764b725ae77Skettenis   st2000_ops.to_shortname = "st2000";
765b725ae77Skettenis   st2000_ops.to_longname = "Remote serial Tandem ST2000 target";
766b725ae77Skettenis   st2000_ops.to_doc = "Use a remote computer running STDEBUG connected by a serial line;\n\
767e93f7393Sniklas or a network connection.\n\
768e93f7393Sniklas Arguments are the name of the device for the serial line,\n\
769b725ae77Skettenis the speed to connect at in bits per second.";
770b725ae77Skettenis   st2000_ops.to_open = st2000_open;
771b725ae77Skettenis   st2000_ops.to_close = st2000_close;
772b725ae77Skettenis   st2000_ops.to_detach = st2000_detach;
773b725ae77Skettenis   st2000_ops.to_resume = st2000_resume;
774b725ae77Skettenis   st2000_ops.to_wait = st2000_wait;
775b725ae77Skettenis   st2000_ops.to_fetch_registers = st2000_fetch_register;
776b725ae77Skettenis   st2000_ops.to_store_registers = st2000_store_register;
777b725ae77Skettenis   st2000_ops.to_prepare_to_store = st2000_prepare_to_store;
778*63addd46Skettenis   st2000_ops.deprecated_xfer_memory = st2000_xfer_inferior_memory;
779b725ae77Skettenis   st2000_ops.to_files_info = st2000_files_info;
780b725ae77Skettenis   st2000_ops.to_insert_breakpoint = st2000_insert_breakpoint;
781b725ae77Skettenis   st2000_ops.to_remove_breakpoint = st2000_remove_breakpoint;	/* Breakpoints */
782b725ae77Skettenis   st2000_ops.to_kill = st2000_kill;
783b725ae77Skettenis   st2000_ops.to_create_inferior = st2000_create_inferior;
784b725ae77Skettenis   st2000_ops.to_mourn_inferior = st2000_mourn_inferior;
785b725ae77Skettenis   st2000_ops.to_stratum = process_stratum;
786b725ae77Skettenis   st2000_ops.to_has_all_memory = 1;
787b725ae77Skettenis   st2000_ops.to_has_memory = 1;
788b725ae77Skettenis   st2000_ops.to_has_stack = 1;
789b725ae77Skettenis   st2000_ops.to_has_registers = 1;
790b725ae77Skettenis   st2000_ops.to_has_execution = 1;	/* all mem, mem, stack, regs, exec */
791b725ae77Skettenis   st2000_ops.to_magic = OPS_MAGIC;	/* Always the last thing */
792e93f7393Sniklas };
793e93f7393Sniklas 
794e93f7393Sniklas void
_initialize_remote_st2000(void)795b725ae77Skettenis _initialize_remote_st2000 (void)
796e93f7393Sniklas {
797b725ae77Skettenis   init_st2000_ops ();
798e93f7393Sniklas   add_target (&st2000_ops);
799e93f7393Sniklas   add_com ("st2000 <command>", class_obscure, st2000_command,
800e93f7393Sniklas 	   "Send a command to the STDBUG monitor.");
801e93f7393Sniklas   add_com ("connect", class_obscure, connect_command,
802e93f7393Sniklas 	   "Connect the terminal directly up to the STDBUG command monitor.\n\
803e93f7393Sniklas Use <CR>~. or <CR>~^D to break out.");
804e93f7393Sniklas }
805