gdb/gdbserver/
[deliverable/binutils-gdb.git] / gdb / gdbserver / remote-utils.c
index 2fccc67595f493700ade909eb0fc8527ddb3da22..3dfd1c9a00314fe617b92dac200f2685ffae48e1 100644 (file)
@@ -80,7 +80,19 @@ typedef int socklen_t;
 # define INVALID_DESCRIPTOR -1
 #endif
 
+/* Extra value for readchar_callback.  */
+enum {
+  /* The callback is currently not scheduled.  */
+  NOT_SCHEDULED = -1
+};
+
+/* Status of the readchar callback.
+   Either NOT_SCHEDULED or the callback id.  */
+static int readchar_callback = NOT_SCHEDULED;
+
 static int readchar (void);
+static void reset_readchar (void);
+static void reschedule (void);
 
 /* A cache entry for a successfully looked-up symbol.  */
 struct sym_cache
@@ -293,7 +305,7 @@ remote_open (char *name)
 #endif
 
       listen_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
-      if (listen_desc < 0)
+      if (listen_desc == -1)
        perror_with_name ("Can't open socket");
 
       /* Allow rapid reuse of this port. */
@@ -341,6 +353,8 @@ remote_close (void)
   close (remote_desc);
 #endif
   remote_desc = INVALID_DESCRIPTOR;
+
+  reset_readchar ();
 }
 
 /* Convert hex digit A to a number.  */
@@ -926,33 +940,83 @@ initialize_async_io (void)
   unblock_async_io ();
 }
 
+/* Internal buffer used by readchar.
+   These are global to readchar because reschedule_remote needs to be
+   able to tell whether the buffer is empty.  */
+
+static unsigned char readchar_buf[BUFSIZ];
+static int readchar_bufcnt = 0;
+static unsigned char *readchar_bufp;
+
 /* Returns next char from remote GDB.  -1 if error.  */
 
 static int
 readchar (void)
 {
-  static unsigned char buf[BUFSIZ];
-  static int bufcnt = 0;
-  static unsigned char *bufp;
+  int ch;
 
-  if (bufcnt-- > 0)
-    return *bufp++;
+  if (readchar_bufcnt == 0)
+    {
+      readchar_bufcnt = read (remote_desc, readchar_buf, sizeof (readchar_buf));
 
-  bufcnt = read (remote_desc, buf, sizeof (buf));
+      if (readchar_bufcnt <= 0)
+       {
+         if (readchar_bufcnt == 0)
+           fprintf (stderr, "readchar: Got EOF\n");
+         else
+           perror ("readchar");
 
-  if (bufcnt <= 0)
-    {
-      if (bufcnt == 0)
-       fprintf (stderr, "readchar: Got EOF\n");
-      else
-       perror ("readchar");
+         return -1;
+       }
 
-      return -1;
+      readchar_bufp = readchar_buf;
+    }
+
+  readchar_bufcnt--;
+  ch = *readchar_bufp++;
+  reschedule ();
+  return ch;
+}
+
+/* Reset the readchar state machine.  */
+
+static void
+reset_readchar (void)
+{
+  readchar_bufcnt = 0;
+  if (readchar_callback != NOT_SCHEDULED)
+    {
+      delete_callback_event (readchar_callback);
+      readchar_callback = NOT_SCHEDULED;
     }
+}
+
+/* Process remaining data in readchar_buf.  */
+
+static int
+process_remaining (void *context)
+{
+  int res;
 
-  bufp = buf;
-  bufcnt--;
-  return *bufp++;
+  /* This is a one-shot event.  */
+  readchar_callback = NOT_SCHEDULED;
+
+  if (readchar_bufcnt > 0)
+    res = handle_serial_event (0, NULL);
+  else
+    res = 0;
+
+  return res;
+}
+
+/* If there is still data in the buffer, queue another event to process it,
+   we can't sleep in select yet.  */
+
+static void
+reschedule (void)
+{
+  if (readchar_bufcnt > 0 && readchar_callback == NOT_SCHEDULED)
+    readchar_callback = append_callback_event (process_remaining, NULL);
 }
 
 /* Read a packet from the remote machine, with error checking,
@@ -1063,7 +1127,7 @@ write_enn (char *buf)
 }
 
 void
-convert_int_to_ascii (unsigned char *from, char *to, int n)
+convert_int_to_ascii (const unsigned char *from, char *to, int n)
 {
   int nib;
   int ch;
@@ -1080,7 +1144,7 @@ convert_int_to_ascii (unsigned char *from, char *to, int n)
 
 
 void
-convert_ascii_to_int (char *from, unsigned char *to, int n)
+convert_ascii_to_int (const char *from, unsigned char *to, int n)
 {
   int nib1, nib2;
   while (n--)
@@ -1290,7 +1354,7 @@ decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr)
 
 void
 decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr,
-                unsigned char *to)
+                unsigned char **to_p)
 {
   int i = 0;
   char ch;
@@ -1308,12 +1372,15 @@ decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr,
       *len_ptr |= fromhex (ch) & 0x0f;
     }
 
-  convert_ascii_to_int (&from[i++], to, *len_ptr);
+  if (*to_p == NULL)
+    *to_p = xmalloc (*len_ptr);
+
+  convert_ascii_to_int (&from[i++], *to_p, *len_ptr);
 }
 
 int
 decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
-                unsigned int *len_ptr, unsigned char *to)
+                unsigned int *len_ptr, unsigned char **to_p)
 {
   int i = 0;
   char ch;
@@ -1331,8 +1398,11 @@ decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
       *len_ptr |= fromhex (ch) & 0x0f;
     }
 
+  if (*to_p == NULL)
+    *to_p = xmalloc (*len_ptr);
+
   if (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i,
-                            to, *len_ptr) != *len_ptr)
+                            *to_p, *len_ptr) != *len_ptr)
     return -1;
 
   return 0;
@@ -1411,11 +1481,12 @@ clear_symbol_cache (struct sym_cache **symcache_p)
   *symcache_p = NULL;
 }
 
-/* Ask GDB for the address of NAME, and return it in ADDRP if found.
+/* Get the address of NAME, and return it in ADDRP if found.  if
+   MAY_ASK_GDB is false, assume symbol cache misses are failures.
    Returns 1 if the symbol is found, 0 if it is not, -1 on error.  */
 
 int
-look_up_one_symbol (const char *name, CORE_ADDR *addrp)
+look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb)
 {
   char own_buf[266], *p, *q;
   int len;
@@ -1432,12 +1503,9 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
        return 1;
       }
 
-  /* If we've passed the call to thread_db_look_up_symbols, then
-     anything not in the cache must not exist; we're not interested
-     in any libraries loaded after that point, only in symbols in
-     libpthread.so.  It might not be an appropriate time to look
-     up a symbol, e.g. while we're trying to fetch registers.  */
-  if (proc->all_symbols_looked_up)
+  /* It might not be an appropriate time to look up a symbol,
+     e.g. while we're trying to fetch registers.  */
+  if (!may_ask_gdb)
     return 0;
 
   /* Send the request.  */
@@ -1503,6 +1571,101 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
   return 1;
 }
 
+/* Relocate an instruction to execute at a different address.  OLDLOC
+   is the address in the inferior memory where the instruction to
+   relocate is currently at.  On input, TO points to the destination
+   where we want the instruction to be copied (and possibly adjusted)
+   to.  On output, it points to one past the end of the resulting
+   instruction(s).  The effect of executing the instruction at TO
+   shall be the same as if executing it at FROM.  For example, call
+   instructions that implicitly push the return address on the stack
+   should be adjusted to return to the instruction after OLDLOC;
+   relative branches, and other PC-relative instructions need the
+   offset adjusted; etc.  Returns 0 on success, -1 on failure.  */
+
+int
+relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
+{
+  char own_buf[266];
+  int len;
+  ULONGEST written = 0;
+
+  /* Send the request.  */
+  strcpy (own_buf, "qRelocInsn:");
+  sprintf (own_buf, "qRelocInsn:%s;%s", paddress (oldloc),
+          paddress (*to));
+  if (putpkt (own_buf) < 0)
+    return -1;
+
+  /* FIXME:  Eventually add buffer overflow checking (to getpkt?)  */
+  len = getpkt (own_buf);
+  if (len < 0)
+    return -1;
+
+  /* We ought to handle pretty much any packet at this point while we
+     wait for the qRelocInsn "response".  That requires re-entering
+     the main loop.  For now, this is an adequate approximation; allow
+     GDB to access memory.  */
+  while (own_buf[0] == 'm' || own_buf[0] == 'M' || own_buf[0] == 'X')
+    {
+      CORE_ADDR mem_addr;
+      unsigned char *mem_buf = NULL;
+      unsigned int mem_len;
+
+      if (own_buf[0] == 'm')
+       {
+         decode_m_packet (&own_buf[1], &mem_addr, &mem_len);
+         mem_buf = xmalloc (mem_len);
+         if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
+           convert_int_to_ascii (mem_buf, own_buf, mem_len);
+         else
+           write_enn (own_buf);
+       }
+      else if (own_buf[0] == 'X')
+       {
+         if (decode_X_packet (&own_buf[1], len - 1, &mem_addr,
+                              &mem_len, &mem_buf) < 0
+             || write_inferior_memory (mem_addr, mem_buf, mem_len) != 0)
+           write_enn (own_buf);
+         else
+           write_ok (own_buf);
+       }
+      else
+       {
+         decode_M_packet (&own_buf[1], &mem_addr, &mem_len, &mem_buf);
+         if (write_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
+           write_ok (own_buf);
+         else
+           write_enn (own_buf);
+       }
+      free (mem_buf);
+      if (putpkt (own_buf) < 0)
+       return -1;
+      len = getpkt (own_buf);
+      if (len < 0)
+       return -1;
+    }
+
+  if (own_buf[0] == 'E')
+    {
+      warning ("An error occurred while relocating an instruction: %s\n",
+              own_buf);
+      return -1;
+    }
+
+  if (strncmp (own_buf, "qRelocInsn:", strlen ("qRelocInsn:")) != 0)
+    {
+      warning ("Malformed response to qRelocInsn, ignoring: %s\n",
+              own_buf);
+      return -1;
+    }
+
+  unpack_varlen_hex (own_buf + strlen ("qRelocInsn:"), &written);
+
+  *to += written;
+  return 0;
+}
+
 void
 monitor_output (const char *msg)
 {
This page took 0.028258 seconds and 4 git commands to generate.