+}
+
+/*
+ * Command: info remote-process
+ *
+ * This implements Cisco's version of the "info proc" command.
+ *
+ * This query allows the target stub to return an arbitrary string
+ * (or strings) giving arbitrary information about the target process.
+ * This is optional; the target stub isn't required to implement it.
+ *
+ * Syntax: qfProcessInfo request first string
+ * qsProcessInfo request subsequent string
+ * reply: 'O'<hex-encoded-string>
+ * 'l' last reply (empty)
+ */
+
+static void
+remote_info_process (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *buf = alloca (PBUFSIZ);
+
+ if (remote_desc == 0)
+ error ("Command can only be used when connected to the remote target.");
+
+ putpkt ("qfProcessInfo");
+ getpkt (buf, 0);
+ if (buf[0] == 0)
+ return; /* Silently: target does not support this feature. */
+
+ if (buf[0] == 'E')
+ error ("info proc: target error.");
+
+ while (buf[0] == 'O') /* Capitol-O packet */
+ {
+ remote_console_output (&buf[1]);
+ putpkt ("qsProcessInfo");
+ getpkt (buf, 0);
+ }
+}
+
+/*
+ * Target Cisco
+ */
+
+static void
+remote_cisco_open (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ if (name == 0)
+ error (
+"To open a remote debug connection, you need to specify what \n\
+device is attached to the remote system (e.g. host:port).");
+
+ target_preopen (from_tty);
+
+ unpush_target (&remote_cisco_ops);
+
+ remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes);
+
+ remote_desc = SERIAL_OPEN (name);
+ if (!remote_desc)
+ perror_with_name (name);
+
+ /*
+ * If a baud rate was specified on the gdb command line it will
+ * be greater than the initial value of -1. If it is, use it otherwise
+ * default to 9600
+ */
+
+ baud_rate = (baud_rate > 0) ? baud_rate : 9600;
+ if (SERIAL_SETBAUDRATE (remote_desc, baud_rate))
+ {
+ SERIAL_CLOSE (remote_desc);
+ perror_with_name (name);
+ }
+
+ SERIAL_RAW (remote_desc);
+
+ /* If there is something sitting in the buffer we might take it as a
+ response to a command, which would be bad. */
+ SERIAL_FLUSH_INPUT (remote_desc);
+
+ if (from_tty)
+ {
+ puts_filtered ("Remote debugging using ");
+ puts_filtered (name);
+ puts_filtered ("\n");
+ }
+
+ remote_cisco_mode = 1;
+
+ push_target (&remote_cisco_ops); /* Switch to using cisco target now */
+
+ /* Start out by trying the 'P' request to set registers. We set this each
+ time that we open a new target so that if the user switches from one
+ stub to another, we can (if the target is closed and reopened) cope. */
+ stub_supports_P = 1;
+
+ general_thread = -2;
+ continue_thread = -2;
+
+ /* Force remote_write_bytes to check whether target supports
+ binary downloading. */
+ remote_binary_checked = 0;
+
+ /* Without this, some commands which require an active target (such
+ as kill) won't work. This variable serves (at least) double duty
+ as both the pid of the target process (if it has such), and as a
+ flag indicating that a target is active. These functions should
+ be split out into seperate variables, especially since GDB will
+ someday have a notion of debugging several processes. */
+ inferior_pid = MAGIC_NULL_PID;
+
+ /* Start the remote connection; if error (0), discard this target. */
+
+ if (!catch_errors (remote_start_remote_dummy, (char *) 0,
+ "Couldn't establish connection to remote target\n",
+ RETURN_MASK_ALL))
+ {
+ pop_target ();
+ return;
+ }
+}
+
+static void
+remote_cisco_close (quitting)
+ int quitting;
+{
+ remote_cisco_mode = 0;
+ remote_close (quitting);
+}
+
+static void
+remote_cisco_mourn PARAMS ((void))
+{
+ remote_mourn_1 (&remote_cisco_ops);
+}
+
+enum {
+ READ_MORE,
+ FATAL_ERROR,
+ ENTER_DEBUG,
+ DISCONNECT_TELNET
+} minitelnet_return;
+
+/* shared between readsocket() and readtty() */
+static char *tty_input;
+
+static int escape_count;
+static int echo_check;
+extern int quit_flag;
+
+static int
+readsocket ()
+{
+ int data;
+
+ /* Loop until the socket doesn't have any more data */
+
+ while ((data = readchar (0)) >= 0)
+ {
+ /* Check for the escape sequence */
+ if (data == '|')
+ {
+ /* If this is the fourth escape, get out */
+ if (++escape_count == 4)
+ {
+ return ENTER_DEBUG;
+ }
+ else
+ { /* This is a '|', but not the fourth in a row.
+ Continue without echoing it. If it isn't actually
+ one of four in a row, it'll be echoed later. */
+ continue;
+ }
+ }
+ else /* Not a '|' */
+ {
+ /* Ensure any pending '|'s are flushed. */
+
+ for ( ; escape_count > 0; escape_count--)
+ putchar('|');
+ }
+
+ if (data == '\r') /* If this is a return character, */
+ continue; /* - just supress it. */
+
+ if (echo_check != -1) /* Check for echo of user input. */
+ {
+ if (tty_input[echo_check] == data)
+ {
+ echo_check++; /* Character matched user input: */
+ continue; /* Continue without echoing it. */
+ }
+ else if ((data == '\n') && (tty_input[echo_check] == '\r'))
+ { /* End of the line (and of echo checking). */
+ echo_check = -1; /* No more echo supression */
+ continue; /* Continue without echoing. */
+ }
+ else
+ { /* Failed check for echo of user input.
+ We now have some suppressed output to flush! */
+ int j;
+
+ for (j = 0; j < echo_check; j++)
+ putchar (tty_input[j]);
+ echo_check = -1;
+ }
+ }
+ putchar (data); /* Default case: output the char. */
+ }
+
+ if (data == SERIAL_TIMEOUT) /* Timeout returned from readchar. */
+ return READ_MORE; /* Try to read some more */
+ else
+ return FATAL_ERROR; /* Trouble, bail out */
+}
+
+static int
+readtty ()
+{
+ int status;
+ int tty_bytecount;
+
+ /* First, read a buffer full from the terminal */
+ tty_bytecount = read (fileno (stdin), tty_input, sizeof (tty_input) - 1);
+ if (tty_bytecount == -1)
+ {
+ perror ("readtty: read failed");
+ return FATAL_ERROR;
+ }
+
+ /* Remove a quoted newline. */
+ if (tty_input[tty_bytecount - 1] == '\n' &&
+ tty_input[tty_bytecount - 2] == '\\') /* line ending in backslash */
+ {
+ tty_input[--tty_bytecount] = 0; /* remove newline */
+ tty_input[--tty_bytecount] = 0; /* remove backslash */
+ }
+
+ /* Turn trailing newlines into returns */
+ if (tty_input[tty_bytecount - 1] == '\n')
+ tty_input[tty_bytecount - 1] = '\r';
+
+ /* If the line consists of a ~, enter debugging mode. */
+ if ((tty_input[0] == '~') && (tty_bytecount == 2))
+ return ENTER_DEBUG;
+
+ /* Make this a zero terminated string and write it out */
+ tty_input[tty_bytecount] = 0;
+ if (SERIAL_WRITE (remote_desc, tty_input, tty_bytecount))
+ {
+ perror_with_name ("readtty: write failed");
+ return FATAL_ERROR;
+ }
+
+ return READ_MORE;
+}
+
+static int
+minitelnet ()
+{
+ fd_set input; /* file descriptors for select */
+ int tablesize; /* max number of FDs for select */
+ int status;
+ int quit_count = 0;
+
+ extern int escape_count; /* global shared by readsocket */
+ extern int echo_check; /* ditto */
+
+ escape_count = 0;
+ echo_check = -1;
+
+ tablesize = 8 * sizeof (input);
+
+ for (;;)
+ {
+ /* Check for anything from our socket - doesn't block. Note that
+ this must be done *before* the select as there may be
+ buffered I/O waiting to be processed. */
+
+ if ((status = readsocket ()) == FATAL_ERROR)
+ {
+ error ("Debugging terminated by communications error");
+ }
+ else if (status != READ_MORE)
+ {
+ return (status);
+ }
+
+ fflush(stdout); /* Flush output before blocking */
+
+ /* Now block on more socket input or TTY input */
+
+ FD_ZERO (&input);
+ FD_SET (fileno(stdin), &input);
+ FD_SET (remote_desc->fd, &input);
+
+ status = select (tablesize, &input, 0, 0, 0);
+ if ((status == -1) && (errno != EINTR))
+ {
+ error ("Communications error on select %d", errno);
+ }
+
+ /* Handle Control-C typed */
+
+ if (quit_flag)
+ {
+ if ((++quit_count) == 2)
+ {
+ if (query ("Interrupt GDB? "))
+ {
+ printf_filtered ("Interrupted by user.\n");
+ return_to_top_level (RETURN_QUIT);
+ }
+ quit_count = 0;
+ }
+ quit_flag = 0;
+
+ if (remote_break)
+ SERIAL_SEND_BREAK (remote_desc);
+ else
+ SERIAL_WRITE (remote_desc, "\003", 1);
+
+ continue;
+ }
+
+ /* Handle console input */
+
+ if (FD_ISSET (fileno (stdin), &input))
+ {
+ quit_count = 0;
+ echo_check = 0;
+ status = readtty ();
+ if (status == READ_MORE)
+ continue;
+
+ return status; /* telnet session ended */
+ }
+ }
+}
+
+static int
+remote_cisco_wait (pid, status)
+ int pid;
+ struct target_waitstatus *status;
+{
+ if (minitelnet() != ENTER_DEBUG)
+ {
+ error ("Debugging session terminated by protocol error");
+ }
+ putpkt ("?");
+ return remote_wait (pid, status);
+}
+
+static void
+init_remote_cisco_ops ()
+{
+ remote_cisco_ops.to_shortname = "cisco";
+ remote_cisco_ops.to_longname = "Remote serial target in cisco-specific protocol";
+ remote_cisco_ops.to_doc =
+ "Use a remote machine via TCP, using a cisco-specific protocol.\n\
+Specify the serial device it is connected to (e.g. host:2020).";
+ remote_cisco_ops.to_open = remote_cisco_open;
+ remote_cisco_ops.to_close = remote_cisco_close;
+ remote_cisco_ops.to_detach = remote_detach;
+ remote_cisco_ops.to_resume = remote_resume;
+ remote_cisco_ops.to_wait = remote_cisco_wait;
+ remote_cisco_ops.to_fetch_registers = remote_fetch_registers;
+ remote_cisco_ops.to_store_registers = remote_store_registers;
+ remote_cisco_ops.to_prepare_to_store = remote_prepare_to_store;
+ remote_cisco_ops.to_xfer_memory = remote_xfer_memory;
+ remote_cisco_ops.to_files_info = remote_files_info;
+ remote_cisco_ops.to_insert_breakpoint = remote_insert_breakpoint;
+ remote_cisco_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ remote_cisco_ops.to_kill = remote_kill;
+ remote_cisco_ops.to_load = generic_load;
+ remote_cisco_ops.to_mourn_inferior = remote_cisco_mourn;
+ remote_cisco_ops.to_thread_alive = remote_thread_alive;
+ remote_cisco_ops.to_find_new_threads = remote_threads_info;
+ remote_cisco_ops.to_stratum = process_stratum;
+ remote_cisco_ops.to_has_all_memory = 1;
+ remote_cisco_ops.to_has_memory = 1;
+ remote_cisco_ops.to_has_stack = 1;
+ remote_cisco_ops.to_has_registers = 1;
+ remote_cisco_ops.to_has_execution = 1;
+ remote_cisco_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+build_remote_gdbarch_data ()
+{
+ tty_input = xmalloc (PBUFSIZ);
+}
+