diff options
Diffstat (limited to 'gdb/remote-st.c')
-rw-r--r-- | gdb/remote-st.c | 800 |
1 files changed, 0 insertions, 800 deletions
diff --git a/gdb/remote-st.c b/gdb/remote-st.c deleted file mode 100644 index c2bcf3d..0000000 --- a/gdb/remote-st.c +++ /dev/null @@ -1,800 +0,0 @@ -/* Remote debugging interface for Tandem ST2000 phone switch, for GDB. - - Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, - 2001, 2002, 2006 Free Software Foundation, Inc. - - Contributed by Cygnus Support. Written by Jim Kingdon for Cygnus. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* This file was derived from remote-eb.c, which did a similar job, but for - an AMD-29K running EBMON. That file was in turn derived from remote.c - as mentioned in the following comment (left in for comic relief): - - "This is like remote.c but is for an esoteric situation-- - having an a29k board in a PC hooked up to a unix machine with - a serial line, and running ctty com1 on the PC, through which - the unix machine can run ebmon. Not to mention that the PC - has PC/NFS, so it can access the same executables that gdb can, - over the net in real time." - - In reality, this module talks to a debug monitor called 'STDEBUG', which - runs in a phone switch. We communicate with STDEBUG via either a direct - serial line, or a TCP (or possibly TELNET) stream to a terminal multiplexor, - which in turn talks to the phone switch. */ - -#include "defs.h" -#include "gdbcore.h" -#include "target.h" -#include "gdb_string.h" -#include <sys/types.h> -#include "serial.h" -#include "regcache.h" - -extern struct target_ops st2000_ops; /* Forward declaration */ - -static void st2000_close (); -static void st2000_fetch_register (); -static void st2000_store_register (); - -#define LOG_FILE "st2000.log" -#if defined (LOG_FILE) -FILE *log_file; -#endif - -static int timeout = 24; - -/* Descriptor for I/O to remote machine. Initialize it to -1 so that - st2000_open knows that we don't have a file open when the program - starts. */ - -static struct serial *st2000_desc; - -/* Send data to stdebug. Works just like printf. */ - -static void -printf_stdebug (char *pattern,...) -{ - va_list args; - char buf[200]; - - va_start (args, pattern); - - vsprintf (buf, pattern, args); - va_end (args); - - if (serial_write (st2000_desc, buf, strlen (buf))) - fprintf_unfiltered (gdb_stderr, "serial_write failed: %s\n", - safe_strerror (errno)); -} - -/* Read a character from the remote system, doing all the fancy timeout - stuff. */ - -static int -readchar (int timeout) -{ - int c; - - c = serial_readchar (st2000_desc, timeout); - -#ifdef LOG_FILE - putc (c & 0x7f, log_file); -#endif - - if (c >= 0) - return c & 0x7f; - - if (c == SERIAL_TIMEOUT) - { - if (timeout == 0) - return c; /* Polls shouldn't generate timeout errors */ - - error (_("Timeout reading from remote system.")); - } - - perror_with_name (_("remote-st2000")); -} - -/* Scan input from the remote system, until STRING is found. If DISCARD is - non-zero, then discard non-matching input, else print it out. - Let the user break out immediately. */ -static void -expect (char *string, int discard) -{ - char *p = string; - int c; - - immediate_quit++; - while (1) - { - c = readchar (timeout); - if (c == *p++) - { - if (*p == '\0') - { - immediate_quit--; - return; - } - } - else - { - if (!discard) - { - fwrite (string, 1, (p - 1) - string, stdout); - putchar ((char) c); - fflush (stdout); - } - p = string; - } - } -} - -/* Keep discarding input until we see the STDEBUG prompt. - - The convention for dealing with the prompt is that you - o give your command - o *then* wait for the prompt. - - Thus the last thing that a procedure does with the serial line - will be an expect_prompt(). Exception: st2000_resume does not - wait for the prompt, because the terminal is being handed over - to the inferior. However, the next thing which happens after that - is a st2000_wait which does wait for the prompt. - Note that this includes abnormal exit, e.g. error(). This is - necessary to prevent getting into states from which we can't - recover. */ -static void -expect_prompt (int discard) -{ -#if defined (LOG_FILE) - /* This is a convenient place to do this. The idea is to do it often - enough that we never lose much data if we terminate abnormally. */ - fflush (log_file); -#endif - expect ("dbug> ", discard); -} - -/* Get a hex digit from the remote system & return its value. - If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ -static int -get_hex_digit (int ignore_space) -{ - int ch; - while (1) - { - ch = readchar (timeout); - 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 (1); - error (_("Invalid hex digit from remote system.")); - } - } -} - -/* Get a byte from stdebug and put it in *BYT. Accept any number - leading spaces. */ -static void -get_hex_byte (char *byt) -{ - int val; - - val = get_hex_digit (1) << 4; - val |= get_hex_digit (0); - *byt = val; -} - -/* Get N 32-bit words from remote, each preceded by a space, - and put them in registers starting at REGNO. */ -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); - regcache_raw_supply (current_regcache, regno++, (char *) &val); - } -} - -/* This is called not only when we first attach, but also when the - user types "run" after having attached. */ -static void -st2000_create_inferior (char *execfile, char *args, char **env, - int from_tty) -{ - int entry_pt; - - if (args && *args) - error (_("Can't pass arguments to remote STDEBUG process")); - - if (execfile == 0 || exec_bfd == 0) - error (_("No executable file specified")); - - entry_pt = (int) bfd_get_start_address (exec_bfd); - -/* The "process" (board) is already stopped awaiting our commands, and - the program is already downloaded. We just set its PC and go. */ - - clear_proceed_status (); - - /* Tell wait_for_inferior that we've started a new process. */ - init_wait_for_inferior (); - - /* Set up the "saved terminal modes" of the inferior - based on what modes we are starting it with. */ - target_terminal_init (); - - /* Install inferior's terminal modes. */ - target_terminal_inferior (); - - /* insert_step_breakpoint (); FIXME, do we need this? */ - write_pc ((CORE_ADDR) entry_pt); -} - -/* Open a connection to a remote debugger. - NAME is the filename used for communication. */ - -static int baudrate = 9600; -static char dev_name[100]; - -static void -st2000_open (char *args, int from_tty) -{ - int n; - char junk[100]; - - target_preopen (from_tty); - - n = sscanf (args, " %s %d %s", dev_name, &baudrate, junk); - - if (n != 2) - error (_("Bad arguments. Usage: target st2000 <device> <speed>\n\ -or target st2000 <host> <port>\n")); - - st2000_close (0); - - st2000_desc = serial_open (dev_name); - - if (!st2000_desc) - perror_with_name (dev_name); - - if (serial_setbaudrate (st2000_desc, baudrate)) - { - serial_close (dev_name); - perror_with_name (dev_name); - } - - serial_raw (st2000_desc); - - push_target (&st2000_ops); - -#if defined (LOG_FILE) - log_file = fopen (LOG_FILE, "w"); - if (log_file == NULL) - perror_with_name ((LOG_FILE)); -#endif - - /* Hello? Are you there? */ - printf_stdebug ("\003"); /* ^C wakes up dbug */ - - expect_prompt (1); - - if (from_tty) - printf ("Remote %s connected to %s\n", target_shortname, - dev_name); -} - -/* Close out all files and local state before this target loses control. */ - -static void -st2000_close (int quitting) -{ - serial_close (st2000_desc); - -#if defined (LOG_FILE) - if (log_file) - { - if (ferror (log_file)) - fprintf_unfiltered (gdb_stderr, "Error writing log file.\n"); - if (fclose (log_file) != 0) - fprintf_unfiltered (gdb_stderr, "Error closing log file.\n"); - } -#endif -} - -/* Terminate the open connection to the remote debugger. - Use this when you want to detach and do something else - with your gdb. */ -static void -st2000_detach (int from_tty) -{ - pop_target (); /* calls st2000_close to do the real work */ - if (from_tty) - printf ("Ending remote %s debugging\n", target_shortname); -} - -/* Tell the remote machine to resume. */ - -static void -st2000_resume (ptid_t ptid, int step, enum target_signal sig) -{ - if (step) - { - printf_stdebug ("ST\r"); - /* Wait for the echo. */ - expect ("ST\r", 1); - } - else - { - printf_stdebug ("GO\r"); - /* Swallow the echo. */ - expect ("GO\r", 1); - } -} - -/* Wait until the remote machine stops, then return, - storing status in STATUS just as `wait' would. */ - -static ptid_t -st2000_wait (ptid_t ptid, struct target_waitstatus *status) -{ - int old_timeout = timeout; - - status->kind = TARGET_WAITKIND_EXITED; - status->value.integer = 0; - - timeout = 0; /* Don't time out -- user program is running. */ - - expect_prompt (0); /* Wait for prompt, outputting extraneous text */ - - status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = TARGET_SIGNAL_TRAP; - - timeout = old_timeout; - - return inferior_ptid; -} - -/* Return the name of register number REGNO in the form input and - output by STDEBUG. Currently, REGISTER_NAME just happens return - exactly what STDEBUG wants. Lets take advantage of that just as - long as possible! */ - -static char * -get_reg_name (int regno) -{ - static char buf[50]; - const char *p; - char *b; - - b = buf; - - for (p = REGISTER_NAME (regno); *p; p++) - *b++ = toupper (*p); - *b = '\000'; - - return buf; -} - -/* Read the remote registers into the block REGS. */ - -static void -st2000_fetch_registers (void) -{ - int regno; - - /* Yeah yeah, I know this is horribly inefficient. But it isn't done - very often... I'll clean it up later. */ - - for (regno = 0; regno <= PC_REGNUM; regno++) - st2000_fetch_register (regno); -} - -/* Fetch register REGNO, or all registers if REGNO is -1. - Returns errno value. */ -static void -st2000_fetch_register (int regno) -{ - if (regno == -1) - st2000_fetch_registers (); - else - { - char *name = get_reg_name (regno); - printf_stdebug ("DR %s\r", name); - expect (name, 1); - expect (" : ", 1); - get_hex_regs (1, regno); - expect_prompt (1); - } - return; -} - -/* Store the remote registers from the contents of the block REGS. */ - -static void -st2000_store_registers (void) -{ - int regno; - - for (regno = 0; regno <= PC_REGNUM; regno++) - st2000_store_register (regno); - - registers_changed (); -} - -/* Store register REGNO, or all if REGNO == 0. - Return errno value. */ -static void -st2000_store_register (int regno) -{ - if (regno == -1) - st2000_store_registers (); - else - { - printf_stdebug ("PR %s %x\r", get_reg_name (regno), - read_register (regno)); - - expect_prompt (1); - } -} - -/* Get ready to modify the registers array. On machines which store - individual registers, this doesn't need to do anything. On machines - which store all the registers in one fell swoop, this makes sure - that registers contains all the registers from the program being - debugged. */ - -static void -st2000_prepare_to_store (void) -{ - /* Do nothing, since we can store individual regs */ -} - -static void -st2000_files_info (void) -{ - printf ("\tAttached to %s at %d baud.\n", - dev_name, baudrate); -} - -/* Copy LEN bytes of data from debugger memory at MYADDR - to inferior's memory at MEMADDR. Returns length moved. */ -static int -st2000_write_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -{ - int i; - - for (i = 0; i < len; i++) - { - printf_stdebug ("PM.B %x %x\r", memaddr + i, myaddr[i]); - expect_prompt (1); - } - return len; -} - -/* Read LEN bytes from inferior memory at MEMADDR. Put the result - at debugger address MYADDR. Returns length moved. */ -static int -st2000_read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len) -{ - int i; - - /* Number of bytes read so far. */ - int count; - - /* Starting address of this pass. */ - unsigned long startaddr; - - /* Number of bytes to read in this pass. */ - int len_this_pass; - - /* Note that this code works correctly if startaddr is just less - than UINT_MAX (well, really CORE_ADDR_MAX if there was such a - thing). That is, something like - st2000_read_bytes (CORE_ADDR_MAX - 4, foo, 4) - works--it never adds len to memaddr and gets 0. */ - /* However, something like - st2000_read_bytes (CORE_ADDR_MAX - 3, foo, 4) - doesn't need to work. Detect it and give up if there's an attempt - to do that. */ - 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); - - printf_stdebug ("DI.L %x %x\r", startaddr, len_this_pass); - expect (": ", 1); - - for (i = 0; i < len_this_pass; i++) - get_hex_byte (&myaddr[count++]); - - expect_prompt (1); - - startaddr += len_this_pass; - } - return len; -} - -/* Transfer LEN bytes between GDB address MYADDR and target address - MEMADDR. If WRITE is non-zero, transfer them to the target, - otherwise transfer them from the target. TARGET is unused. - - Returns the number of bytes transferred. */ - -static int -st2000_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len, - int write, struct mem_attrib *attrib, - struct target_ops *target) -{ - if (write) - return st2000_write_inferior_memory (memaddr, myaddr, len); - else - return st2000_read_inferior_memory (memaddr, myaddr, len); -} - -static void -st2000_kill (char *args, int from_tty) -{ - return; /* Ignore attempts to kill target system */ -} - -/* Clean up when a program exits. - - The program actually lives on in the remote processor's RAM, and may be - run again without a download. Don't leave it full of breakpoint - instructions. */ - -static void -st2000_mourn_inferior (void) -{ - remove_breakpoints (); - unpush_target (&st2000_ops); - generic_mourn_inferior (); /* Do all the proper things now */ -} - -#define MAX_STDEBUG_BREAKPOINTS 16 - -static CORE_ADDR breakaddr[MAX_STDEBUG_BREAKPOINTS] = -{0}; - -static int -st2000_insert_breakpoint (struct bp_target_info *bp_tgt) -{ - CORE_ADDR addr = bp_tgt->placed_address; - int i; - - for (i = 0; i <= MAX_STDEBUG_BREAKPOINTS; i++) - if (breakaddr[i] == 0) - { - breakaddr[i] = addr; - - printf_stdebug ("BR %x H\r", addr); - expect_prompt (1); - return 0; - } - - fprintf_unfiltered (gdb_stderr, "Too many breakpoints (> 16) for STDBUG\n"); - return 1; -} - -static int -st2000_remove_breakpoint (struct bp_target_info *bp_tgt) -{ - CORE_ADDR addr = bp_tgt->placed_address; - int i; - - for (i = 0; i < MAX_STDEBUG_BREAKPOINTS; i++) - if (breakaddr[i] == addr) - { - breakaddr[i] = 0; - - printf_stdebug ("CB %d\r", i); - expect_prompt (1); - return 0; - } - - fprintf_unfiltered (gdb_stderr, - "Can't find breakpoint associated with 0x%x\n", addr); - return 1; -} - - -/* Put a command string, in args, out to STDBUG. Output from STDBUG is placed - on the users terminal until the prompt is seen. */ - -static void -st2000_command (char *args, int fromtty) -{ - if (!st2000_desc) - error (_("st2000 target not open.")); - - if (!args) - error (_("Missing command.")); - - printf_stdebug ("%s\r", args); - expect_prompt (0); -} - -/* Connect the user directly to STDBUG. This command acts just like the - 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */ - -/*static struct ttystate ttystate; */ - -static void -cleanup_tty (void) -{ - printf ("\r\n[Exiting connect mode]\r\n"); -/* serial_restore(0, &ttystate); */ -} - -#if 0 -/* This all should now be in serial.c */ - -static void -connect_command (char *args, int fromtty) -{ - fd_set readfds; - int numfds; - int c; - char cur_esc = 0; - - dont_repeat (); - - if (st2000_desc < 0) - error (_("st2000 target not open.")); - - if (args) - fprintf ("This command takes no args. They have been ignored.\n"); - - printf ("[Entering connect mode. Use ~. or ~^D to escape]\n"); - - serial_raw (0, &ttystate); - - make_cleanup (cleanup_tty, 0); - - FD_ZERO (&readfds); - - while (1) - { - do - { - FD_SET (0, &readfds); - FD_SET (deprecated_serial_fd (st2000_desc), &readfds); - numfds = gdb_select (sizeof (readfds) * 8, &readfds, 0, 0, 0); - } - while (numfds == 0); - - if (numfds < 0) - perror_with_name (("select")); - - if (FD_ISSET (0, &readfds)) - { /* tty input, send to stdebug */ - c = getchar (); - if (c < 0) - perror_with_name (("connect")); - - printf_stdebug ("%c", c); - switch (cur_esc) - { - case 0: - if (c == '\r') - cur_esc = c; - break; - case '\r': - if (c == '~') - cur_esc = c; - else - cur_esc = 0; - break; - case '~': - if (c == '.' || c == '\004') - return; - else - cur_esc = 0; - } - } - - if (FD_ISSET (deprecated_serial_fd (st2000_desc), &readfds)) - { - while (1) - { - c = readchar (0); - if (c < 0) - break; - putchar (c); - } - fflush (stdout); - } - } -} -#endif /* 0 */ - -/* Define the target subroutine names */ - -struct target_ops st2000_ops; - -static void -init_st2000_ops (void) -{ - st2000_ops.to_shortname = "st2000"; - st2000_ops.to_longname = "Remote serial Tandem ST2000 target"; - st2000_ops.to_doc = "Use a remote computer running STDEBUG connected by a serial line;\n\ -or a network connection.\n\ -Arguments are the name of the device for the serial line,\n\ -the speed to connect at in bits per second."; - st2000_ops.to_open = st2000_open; - st2000_ops.to_close = st2000_close; - st2000_ops.to_detach = st2000_detach; - st2000_ops.to_resume = st2000_resume; - st2000_ops.to_wait = st2000_wait; - st2000_ops.to_fetch_registers = st2000_fetch_register; - st2000_ops.to_store_registers = st2000_store_register; - st2000_ops.to_prepare_to_store = st2000_prepare_to_store; - st2000_ops.deprecated_xfer_memory = st2000_xfer_inferior_memory; - st2000_ops.to_files_info = st2000_files_info; - st2000_ops.to_insert_breakpoint = st2000_insert_breakpoint; - st2000_ops.to_remove_breakpoint = st2000_remove_breakpoint; /* Breakpoints */ - st2000_ops.to_kill = st2000_kill; - st2000_ops.to_create_inferior = st2000_create_inferior; - st2000_ops.to_mourn_inferior = st2000_mourn_inferior; - st2000_ops.to_stratum = process_stratum; - st2000_ops.to_has_all_memory = 1; - st2000_ops.to_has_memory = 1; - st2000_ops.to_has_stack = 1; - st2000_ops.to_has_registers = 1; - st2000_ops.to_has_execution = 1; /* all mem, mem, stack, regs, exec */ - st2000_ops.to_magic = OPS_MAGIC; /* Always the last thing */ -}; - -void -_initialize_remote_st2000 (void) -{ - init_st2000_ops (); - add_target (&st2000_ops); - add_com ("st2000", class_obscure, st2000_command, - _("Send a command to the STDBUG monitor.")); - add_com ("connect", class_obscure, connect_command, _("\ -Connect the terminal directly up to the STDBUG command monitor.\n\ -Use <CR>~. or <CR>~^D to break out.")); -} |