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