* test-build.mk (HOLES): Add "xargs" for gdb.
[deliverable/binutils-gdb.git] / gdb / remote-e7000.c
index b4aaaed310e408614f99fc835c4c4a0a696aacba..7088e8b2a9180ada921cbf7f07b0b58134771d0b 100644 (file)
@@ -1,5 +1,5 @@
 /* Remote debugging interface for Hitachi E7000 ICE, for GDB
-   Copyright 1993, 1994 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1996 Free Software Foundation, Inc.
    Contributed by Cygnus Support. 
 
    Written by Steve Chamberlain for Cygnus Support.
@@ -18,7 +18,7 @@
 
    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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* The E7000 is an in-circuit emulator for the Hitachi H8/300-H and
    Hitachi-SH processor.  It has serial port and a lan port.  
 #include "command.h"
 #include <signal.h>
 #include "gdb_string.h"
+#include "gdbcmd.h"
 #include <sys/types.h>
 #include "serial.h"
 #include "remote-utils.h"
+#include "symfile.h"
+#include <time.h>
 
-#if 0
-#define HARD_BREAKPOINTS
-#define BC_BREAKPOINTS 0
+#if 1
+#define HARD_BREAKPOINTS       /* Now handled by set option. */
+#define BC_BREAKPOINTS use_hard_breakpoints
 #endif
 
 #define CTRLC 0x03
 #define ACK  0x06
 #define CTRLZ 0x1a
 
-extern void notice_quit PARAMS ((void));
+extern void report_transfer_performance PARAMS ((unsigned long,
+                                                time_t, time_t));
+
+extern char *sh_processor_type;
 
 /* Local function declarations.  */
 
@@ -82,9 +88,14 @@ static void expect_prompt PARAMS ((void));
 
 static serial_t e7000_desc;
 
+/* Allow user to chose between using hardware breakpoints or memory. */
+static int use_hard_breakpoints = 0; /* use sw breakpoints by default */
+
 /* Nonzero if using the tcp serial driver.  */
 
-static int using_tcp;
+static int using_tcp;  /* direct tcp connection to target */
+static int using_tcp_remote;   /* indirect connection to target 
+                                  via tcp to controller */
 
 /* Nonzero if using the pc isa card.  */
 
@@ -101,7 +112,7 @@ static int echo;
 
 static int ctrl_c;
 
-static int timeout = 5;
+static int timeout = 20;
 
 /* Send data to e7000debug.  */
 
@@ -460,7 +471,7 @@ e7000_ftp_command (args, from_tty)
   char buf[200];
 
   int oldtimeout = timeout;
-  timeout = 10;
+  timeout = remote_timeout;
 
   sprintf (buf, "ftp %s\r", machine);
   puts_e7000debug (buf);
@@ -483,25 +494,32 @@ e7000_ftp_command (args, from_tty)
   timeout = oldtimeout;
 }
 
-static void
-e7000_open (args, from_tty)
-     char *args;
-     int from_tty;
+static int 
+e7000_parse_device(args,dev_name,serial_flag,baudrate) 
+    char *args;
+    char *dev_name;
+    int serial_flag;
+    int baudrate;
 {
-  int n;
-  int loop;
-  char junk[100];
-  int sync;
-  target_preopen (from_tty);
-
-  n = 0;
+  char junk[128];
+  int n = 0;
   if (args && strcasecmp (args, "pc") == 0)
     {
       strcpy (dev_name, args);
+      using_pc = 1;
     }
   else 
     {
-      if (args) 
+      /* FIXME! temp hack to allow use with port master -
+            target tcp_remote <device> */
+      if (args && strncmp (args, "tcp_remote", 10) == 0) 
+        {
+         char com_type[128];
+         n = sscanf (args, " %s %s %d %s", com_type, dev_name, &baudrate, junk);
+         using_tcp_remote=1;
+         n--;
+        }
+      else if (args) 
        {
          n = sscanf (args, " %s %d %s", dev_name, &baudrate, junk);
        }
@@ -510,18 +528,40 @@ e7000_open (args, from_tty)
        {
          error ("Bad arguments.  Usage:\ttarget e7000 <device> <speed>\n\
 or \t\ttarget e7000 <host>[:<port>]\n\
+or \t\ttarget e7000 tcp_remote <host>[:<port>]\n\
 or \t\ttarget e7000 pc\n");
        }
 
-#ifndef __GO32__
+#if !defined(__GO32__) && !defined(__WIN32__)
+      /* FIXME!  test for ':' is ambiguous */
       if (n == 1 && strchr (dev_name, ':') == 0)
        {
          /* Default to normal telnet port */
+         /* serial_open will use this to determine tcp communication */
          strcat (dev_name, ":23");
        }
 #endif
+      if (!using_tcp_remote && strchr (dev_name, ':'))
+        using_tcp = 1;
     }
 
+  return n;
+}
+
+static void
+e7000_open (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  int n;
+  int loop;
+  int sync;
+  int serial_flag;
+
+  target_preopen (from_tty);
+
+  n = e7000_parse_device(args,dev_name,serial_flag,baudrate);
+
   push_target (&e7000_ops);
 
   e7000_desc = SERIAL_OPEN (dev_name);
@@ -529,9 +569,6 @@ or \t\ttarget e7000 pc\n");
   if (!e7000_desc)
     perror_with_name (dev_name);
 
-  using_tcp = strcmp (e7000_desc->ops->name, "tcp") == 0;
-  using_pc = strcmp (e7000_desc->ops->name, "pc") == 0;
-
   SERIAL_SETBAUDRATE (e7000_desc, baudrate);
   SERIAL_RAW (e7000_desc);
 
@@ -580,8 +617,12 @@ or \t\ttarget e7000 pc\n");
 
   expect_prompt ();
 
+  puts_e7000debug ("b -\r");
+
+  expect_prompt ();
+
   if (from_tty)
-    printf_filtered ("Remote %s connected to %s\n", target_shortname,
+    printf_filtered ("Remote target %s connected to %s\n", target_shortname,
                     dev_name);
 
 #ifdef GDB_TARGET_IS_H8300
@@ -664,6 +705,26 @@ char *want_nopc = "%16 SR=%22\n\
  R0-7  %0 %1 %2 %3 %4 %5 %6 %7\n\
  R8-15 %8 %9 %10 %11 %12 %13 %14 %15";
 
+char *want_sh3 = "PC=%16 SR=%22\n\
+PR=%17 GBR=%18 VBR=%19\n\
+MACH=%20 MACL=%21 SSR=%23 SPC=%24\n\
+R0-7  %0 %1 %2 %3 %4 %5 %6 %7\n\
+R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\
+R0_BANK0-R3_BANK0 %25 %26 %27 %28\n\
+R4_BANK0-R7_BANK0 %29 %30 %31 %32\n\
+R0_BANK1-R3_BANK1 %33 %34 %35 %36\n\
+R4_BANK1-R7_BANK1 %37 %38 %39 %40";
+
+char *want_sh3_nopc = "%16 SR=%22\n\
+ PR=%17 GBR=%18 VBR=%19\n\
+ MACH=%20 MACL=%21 SSR=%22 SPC=%23\n\
+ R0-7  %0 %1 %2 %3 %4 %5 %6 %7\n\
+ R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\
+ R0_BANK0-R3_BANK0 %25 %26 %27 %28\n\
+ R4_BANK0-R7_BANK0 %29 %30 %31 %32\n\
+ R0_BANK1-R3_BANK1 %33 %34 %35 %36\n\
+ R4_BANK1-R7_BANK1 %37 %38 %39 %40";
+
 #endif
 
 static int
@@ -803,7 +864,16 @@ e7000_fetch_registers ()
   int regno;
 
   puts_e7000debug ("R\r");
+
+#ifdef GDB_TARGET_IS_SH
+  if  ((sh_processor_type != NULL) && (*(sh_processor_type+2) == '3')) 
+     fetch_regs_from_dump (gch, want_sh3);
+  else
+     fetch_regs_from_dump (gch, want);
+#else
   fetch_regs_from_dump (gch, want);
+#endif
+
 
   /* And supply the extra ones the simulator uses */
   for (regno = NUM_REALREGS; regno < NUM_REGS; regno++)
@@ -1176,7 +1246,7 @@ e7000_read_inferior_memory (memaddr, myaddr, len)
 }
 
 
-#if 0
+
 /*
   For large transfers we used to send
 
@@ -1184,10 +1254,10 @@ e7000_read_inferior_memory (memaddr, myaddr, len)
   d <addr> <endaddr>\r
 
   and receive
-   <ADDR>              <    D   A   T   A    >               <   ASCII CODE   >
-   000000  5F FD FD FF DF 7F DF FF  01 00 01 00 02 00 08 04  "_..............."
-   000010  FF D7 FF 7F D7 F1 7F FF  00 05 00 00 08 00 40 00  "..............@."
-   000020  7F FD FF F7 7F FF FF F7  00 00 00 00 00 00 00 00  "................"
+   <ADDRESS>           <    D   A   T   A    >               <   ASCII CODE   >
+   00000000 5F FD FD FF DF 7F DF FF  01 00 01 00 02 00 08 04  "_..............."
+   00000010 FF D7 FF 7F D7 F1 7F FF  00 05 00 00 08 00 40 00  "..............@."
+   00000020 7F FD FF F7 7F FF FF F7  00 00 00 00 00 00 00 00  "................"
 
   A cost in chars for each transaction of 80 + 5*n-bytes. 
 
@@ -1197,7 +1267,7 @@ e7000_read_inferior_memory (memaddr, myaddr, len)
 */
 
 static int
-e7000_read_inferior_memory (memaddr, myaddr, len)
+e7000_read_inferior_memory_large (memaddr, myaddr, len)
      CORE_ADDR memaddr;
      unsigned char *myaddr;
      int len;
@@ -1219,29 +1289,22 @@ e7000_read_inferior_memory (memaddr, myaddr, len)
 
   count = 0;
   c = gch ();
-
-  /* First skip the command */
-  while (c == '\n')
-    c = gch ();
-
-  while (c == ' ')
+  
+  /* skip down to the first ">" */
+  while( c != '>' )
     c = gch ();
-  if (c == '*')
-    {
-      expect ("\r");
-      return -1;
-    }
-
-  /* Skip the title line */
-  while (c != '\n')
+  /* now skip to the end of that line */
+  while( c != '\r' )
     c = gch ();
   c = gch ();
+
   while (count < len)
     {
-      /* Skip the address */
+      /* get rid of any white space before the address */
       while (c <= ' ')
        c = gch ();
 
+      /* Skip the address */
       get_hex (&c);
 
       /* read in the bytes on the line */
@@ -1254,17 +1317,20 @@ e7000_read_inferior_memory (memaddr, myaddr, len)
              myaddr[count++] = get_hex (&c);
            }
        }
-
-      while (c != '\n')
+      /* throw out the rest of the line */
+      while( c != '\r' )
        c = gch ();
     }
 
+  /* wait for the ":" prompt */
   while (c != ':')
     c = gch ();
 
   return len;
 }
 
+#if 0
+
 static int
 fast_but_for_the_pause_e7000_read_inferior_memory (memaddr, myaddr, len)
      CORE_ADDR memaddr;
@@ -1365,8 +1431,11 @@ e7000_xfer_inferior_memory (memaddr, myaddr, len, write, target)
 {
   if (write)
     return e7000_write_inferior_memory( memaddr, myaddr, len);
-  else
-    return e7000_read_inferior_memory( memaddr, myaddr, len);
+  else 
+    if( len < 16 )
+      return e7000_read_inferior_memory( memaddr, myaddr, len);
+    else
+      return e7000_read_inferior_memory_large( memaddr, myaddr, len);
 }
 
 static void
@@ -1376,6 +1445,187 @@ e7000_kill (args, from_tty)
 {
 }
 
+static void
+e7000_load (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  struct cleanup *old_chain;
+  asection *section;
+  bfd *pbfd;
+  bfd_vma entry;
+  int i;
+#define WRITESIZE 0x1000
+  char buf[2 + 4 + 4 + WRITESIZE]; /* `DT' + <addr> + <len> + <data> */
+  char *filename;
+  int quiet;
+  int nostart;
+  time_t start_time, end_time; /* Start and end times of download */
+  unsigned long data_count;    /* Number of bytes transferred to memory */
+  int oldtimeout = timeout;    
+
+  timeout = remote_timeout;
+
+
+  /* FIXME! change test to test for type of download */
+  if (!using_tcp)
+    {
+      generic_load (args, from_tty);
+      return;
+    }
+
+  /* for direct tcp connections, we can do a fast binary download */
+  buf[0] = 'D';
+  buf[1] = 'T';
+  quiet = 0;
+  nostart = 0;
+  filename = NULL;
+
+  while (*args != '\000')
+    {
+      char *arg;
+
+      while (isspace (*args)) args++;
+
+      arg = args;
+
+      while ((*args != '\000') && !isspace (*args)) args++;
+
+      if (*args != '\000')
+       *args++ = '\000';
+
+      if (*arg != '-')
+       filename = arg;
+      else if (strncmp (arg, "-quiet", strlen (arg)) == 0)
+       quiet = 1;
+      else if (strncmp (arg, "-nostart", strlen (arg)) == 0)
+       nostart = 1;
+      else
+       error ("unknown option `%s'", arg);
+    }
+
+  if (!filename)
+    filename = get_exec_file (1);
+
+  pbfd = bfd_openr (filename, gnutarget);
+  if (pbfd == NULL)
+    {
+      perror_with_name (filename);
+      return;
+    }
+  old_chain = make_cleanup (bfd_close, pbfd);
+
+  if (!bfd_check_format (pbfd, bfd_object)) 
+    error ("\"%s\" is not an object file: %s", filename,
+          bfd_errmsg (bfd_get_error ()));
+
+  start_time = time (NULL);
+  data_count = 0;
+
+  puts_e7000debug ("mw\r");
+
+  expect ("\nOK");
+
+  for (section = pbfd->sections; section; section = section->next) 
+    {
+      if (bfd_get_section_flags (pbfd, section) & SEC_LOAD)
+       {
+         bfd_vma section_address;
+         bfd_size_type section_size;
+         file_ptr fptr;
+
+         section_address = bfd_get_section_vma (pbfd, section);
+         section_size = bfd_get_section_size_before_reloc (section);
+
+         if (!quiet)
+           printf_filtered ("[Loading section %s at 0x%x (%d bytes)]\n",
+                            bfd_get_section_name (pbfd, section),
+                            section_address,
+                            section_size);
+
+         fptr = 0;
+         
+         data_count += section_size;
+
+         while (section_size > 0)
+           {
+             int count;
+             static char inds[] = "|/-\\";
+             static int k = 0;
+
+             QUIT;
+
+             count = min (section_size, WRITESIZE);
+
+             buf[2] = section_address >> 24;
+             buf[3] = section_address >> 16;
+             buf[4] = section_address >> 8;
+             buf[5] = section_address;
+
+             buf[6] = count >> 24;
+             buf[7] = count >> 16;
+             buf[8] = count >> 8;
+             buf[9] = count;
+
+             bfd_get_section_contents (pbfd, section, buf + 10, fptr, count);
+
+             if (SERIAL_WRITE (e7000_desc, buf, count + 10))
+               fprintf_unfiltered (gdb_stderr,
+                                   "e7000_load: SERIAL_WRITE failed: %s\n",
+                                   safe_strerror(errno));
+
+             expect ("OK");
+
+             if (!quiet)
+               {
+                 printf_unfiltered ("\r%c", inds[k++ % 4]);
+                 gdb_flush (gdb_stdout);
+               }
+
+             section_address += count;
+             fptr += count;
+             section_size -= count;
+           }
+       }
+    }
+
+  write_e7000 ("ED");
+
+  expect_prompt ();
+
+  end_time = time (NULL);
+
+/* Finally, make the PC point at the start address */
+
+  if (exec_bfd)
+    write_pc (bfd_get_start_address (exec_bfd));
+
+  inferior_pid = 0;            /* No process now */
+
+/* This is necessary because many things were based on the PC at the time that
+   we attached to the monitor, which is no longer valid now that we have loaded
+   new code (and just changed the PC).  Another way to do this might be to call
+   normal_stop, except that the stack may not be valid, and things would get
+   horribly confused... */
+
+  clear_symtab_users ();
+
+  if (!nostart)
+    {
+      entry = bfd_get_start_address (pbfd);
+
+      if (!quiet)
+       printf_unfiltered ("[Starting %s at 0x%x]\n", filename, entry);
+
+/*      start_routine (entry);*/
+    }
+
+  report_transfer_performance (data_count, start_time, end_time);
+
+  do_cleanups (old_chain);
+  timeout = oldtimeout;
+}
+
 /* Clean up when a program exits.
 
    The program actually lives on in the remote processor's RAM, and may be
@@ -1390,15 +1640,18 @@ e7000_mourn_inferior ()
   generic_mourn_inferior ();   /* Do all the proper things now */
 }
 
+#define MAX_BREAKPOINTS 200
 #ifdef  HARD_BREAKPOINTS
-#define MAX_E7000DEBUG_BREAKPOINTS (BC_BREAKPOINTS ? 5 :  200)
+#define MAX_E7000DEBUG_BREAKPOINTS (BC_BREAKPOINTS ? 5 :  MAX_BREAKPOINTS)
 #else
-#define MAX_E7000DEBUG_BREAKPOINTS 200
+#define MAX_E7000DEBUG_BREAKPOINTS MAX_BREAKPOINTS
 #endif
 
 extern int memory_breakpoint_size;
 
-static CORE_ADDR breakaddr[MAX_E7000DEBUG_BREAKPOINTS] = {0};
+/* Since we can change to soft breakpoints dynamically, we must define 
+   more than enough.  Was breakaddr[MAX_E7000DEBUG_BREAKPOINTS]. */
+static CORE_ADDR breakaddr[MAX_BREAKPOINTS] = {0};
 
 static int
 e7000_insert_breakpoint (addr, shadow)
@@ -1426,8 +1679,10 @@ e7000_insert_breakpoint (addr, shadow)
            puts_e7000debug (buf);
          }
 #else
+#if 0
        e7000_read_inferior_memory (addr, shadow, 2);
        e7000_write_inferior_memory (addr, nop, 2);
+#endif
 
        sprintf (buf, "B %x\r", addr);
        puts_e7000debug (buf);
@@ -1470,8 +1725,10 @@ e7000_remove_breakpoint (addr, shadow)
        puts_e7000debug (buf);
        expect_prompt ();
 
+#if 0
        /* Replace the insn under the break */
        e7000_write_inferior_memory (addr, shadow, 2);
+#endif
 #endif
 
        return 0;
@@ -1517,13 +1774,6 @@ e7000_command (args, fromtty)
   registers_changed ();
 }
 
-static void
-e7000_load (args, fromtty)
-     char *args;
-     int fromtty;
-{
-  gr_load_image (args, fromtty);
-}
 
 static void
 e7000_drain_command (args, fromtty)
@@ -1758,7 +2008,15 @@ e7000_wait (pid, status)
 
   /* Skip till the PC= */
   expect ("=");
+
+#ifdef GDB_TARGET_IS_SH
+  if  ((sh_processor_type != NULL) && (*(sh_processor_type+2) == '3')) 
+     fetch_regs_from_dump (gch, want_sh3_nopc);
+  else
+     fetch_regs_from_dump (gch, want_nopc);
+#else
   fetch_regs_from_dump (gch, want_nopc);
+#endif
 
   /* And supply the extra ones the simulator uses */
   for (regno = NUM_REALREGS; regno < NUM_REGS; regno++)
@@ -1776,6 +2034,7 @@ e7000_wait (pid, status)
   switch (stop_reason)
     {
     case 1:                    /* Breakpoint */
+      write_pc (read_pc ()); /* PC is always off by 2 for breakpoints */
       status->value.sig = TARGET_SIGNAL_TRAP;      
       break;
     case 0:                    /* Single step */
@@ -1816,6 +2075,15 @@ e7000_wait (pid, status)
   return 0;
 }
 
+/* Stop the running program.  */
+
+static void
+e7000_stop ()  
+{
+  /* Sending a ^C is supposed to stop the running program.  */
+  putchar_e7000 (CTRLC);
+}
+
 /* Define the target subroutine names. */
 
 struct target_ops e7000_ops =
@@ -1840,13 +2108,8 @@ target e7000 foobar",
   e7000_prepare_to_store,      /* to_prepare_to_store */
   e7000_xfer_inferior_memory,  /* to_xfer_memory */
   e7000_files_info,            /* to_files_info */
-#ifdef HARD_BREAKPOINTS
   e7000_insert_breakpoint,     /* to_insert_breakpoint */
   e7000_remove_breakpoint,     /* to_remove_breakpoint */
-#else
-  memory_insert_breakpoint,    /* to_insert_breakpoint */
-  memory_remove_breakpoint,    /* to_remove_breakpoint */
-#endif
   0,                           /* to_terminal_init */
   0,                           /* to_terminal_inferior */
   0,                           /* to_terminal_ours_for_output */
@@ -1860,7 +2123,7 @@ target e7000 foobar",
   0,                           /* to_can_run */
   0,                           /* to_notice_signals */
   0,                           /* to_thread_alive */
-  0,                           /* to_stop */
+  e7000_stop,                  /* to_stop */
   process_stratum,             /* to_stratum */
   0,                           /* next (unused) */
   1,                           /* to_has_all_memory */
@@ -1889,4 +2152,9 @@ _initialize_remote_e7000 ()
 
   add_com ("drain", class_obscure, e7000_drain_command,
           "Drain pending e7000 text buffers.");
+
+  add_show_from_set (add_set_cmd ("usehardbreakpoints", no_class,
+                                 var_integer, (char *)&use_hard_breakpoints,
+                                 "Set use of hardware breakpoints for all breakpoints.\n", &setlist),
+                    &showlist);
 }
This page took 0.032319 seconds and 4 git commands to generate.