gnulib: define the path to gnulib's parent dir
[binutils-gdb.git] / gdbserver / server.cc
index d45154d1f54777d25b4f53a2f09e35ef1329dc51..32dcc05924e147b652f33ee1a1b4b5cc9952aa14 100644 (file)
@@ -1,5 +1,5 @@
 /* Main code for remote server for GDB.
-   Copyright (C) 1989-2020 Free Software Foundation, Inc.
+   Copyright (C) 1989-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -49,6 +49,7 @@
 #include "gdbsupport/scope-exit.h"
 #include "gdbsupport/gdb_select.h"
 #include "gdbsupport/scoped_restore.h"
+#include "gdbsupport/search.h"
 
 #define require_running_or_return(BUF)         \
   if (!target_running ())                      \
@@ -202,6 +203,15 @@ discard_queued_stop_replies (ptid_t ptid)
       next = iter;
       ++next;
 
+      if (iter == notif_stop.queue.begin ())
+       {
+         /* The head of the list contains the notification that was
+            already sent to GDB.  So we can't remove it, otherwise
+            when GDB sends the vStopped, it would ack the _next_
+            notification, which hadn't been sent yet!  */
+         continue;
+       }
+
       if (remove_all_on_match_ptid (*iter, ptid))
        {
          delete *iter;
@@ -546,6 +556,64 @@ handle_btrace_conf_general_set (char *own_buf)
   return 1;
 }
 
+/* Create the qMemTags packet reply given TAGS.
+
+   Returns true if parsing succeeded and false otherwise.  */
+
+static bool
+create_fetch_memtags_reply (char *reply, const gdb::byte_vector &tags)
+{
+  /* It is an error to pass a zero-sized tag vector.  */
+  gdb_assert (tags.size () != 0);
+
+  std::string packet ("m");
+
+  /* Write the tag data.  */
+  packet += bin2hex (tags.data (), tags.size ());
+
+  /* Check if the reply is too big for the packet to handle.  */
+  if (PBUFSIZ < packet.size ())
+    return false;
+
+  strcpy (reply, packet.c_str ());
+  return true;
+}
+
+/* Parse the QMemTags request into ADDR, LEN and TAGS.
+
+   Returns true if parsing succeeded and false otherwise.  */
+
+static bool
+parse_store_memtags_request (char *request, CORE_ADDR *addr, size_t *len,
+                            gdb::byte_vector &tags, int *type)
+{
+  gdb_assert (startswith (request, "QMemTags:"));
+
+  const char *p = request + strlen ("QMemTags:");
+
+  /* Read address and length.  */
+  unsigned int length = 0;
+  p = decode_m_packet_params (p, addr, &length, ':');
+  *len = length;
+
+  /* Read the tag type.  */
+  ULONGEST tag_type = 0;
+  p = unpack_varlen_hex (p, &tag_type);
+  *type = (int) tag_type;
+
+  /* Make sure there is a colon after the type.  */
+  if (*p != ':')
+    return false;
+
+  /* Skip the colon.  */
+  p++;
+
+  /* Read the tag data.  */
+  tags = hex2bin (p);
+
+  return true;
+}
+
 /* Handle all of the extended 'Q' packets.  */
 
 static void
@@ -828,8 +896,10 @@ handle_general_set (char *own_buf)
       else
        {
          /* We don't know what this mode is, so complain to GDB.  */
-         sprintf (own_buf, "E.Unknown thread-events mode requested: %s\n",
-                  mode);
+         std::string err
+           = string_printf ("E.Unknown thread-events mode requested: %s\n",
+                            mode);
+         strcpy (own_buf, err.c_str ());
          return;
        }
 
@@ -900,6 +970,32 @@ handle_general_set (char *own_buf)
       return;
     }
 
+
+  /* Handle store memory tags packets.  */
+  if (startswith (own_buf, "QMemTags:")
+      && target_supports_memory_tagging ())
+    {
+      gdb::byte_vector tags;
+      CORE_ADDR addr = 0;
+      size_t len = 0;
+      int type = 0;
+
+      require_running_or_return (own_buf);
+
+      bool ret = parse_store_memtags_request (own_buf, &addr, &len, tags,
+                                            &type);
+
+      if (ret)
+       ret = the_target->store_memtags (addr, len, tags, type);
+
+      if (!ret)
+       write_enn (own_buf);
+      else
+       write_ok (own_buf);
+
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -955,6 +1051,8 @@ monitor_show_help (void)
   monitor_output ("    Enable h/w breakpoint/watchpoint debugging messages\n");
   monitor_output ("  set remote-debug <0|1>\n");
   monitor_output ("    Enable remote protocol debugging messages\n");
+  monitor_output ("  set event-loop-debug <0|1>\n");
+  monitor_output ("    Enable event loop debugging messages\n");
   monitor_output ("  set debug-format option1[,option2,...]\n");
   monitor_output ("    Add additional information to debugging messages\n");
   monitor_output ("    Options: all, none");
@@ -1038,89 +1136,6 @@ gdb_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
     }
 }
 
-/* Subroutine of handle_search_memory to simplify it.  */
-
-static int
-handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
-                       gdb_byte *pattern, unsigned pattern_len,
-                       gdb_byte *search_buf,
-                       unsigned chunk_size, unsigned search_buf_size,
-                       CORE_ADDR *found_addrp)
-{
-  /* Prime the search buffer.  */
-
-  if (gdb_read_memory (start_addr, search_buf, search_buf_size)
-      != search_buf_size)
-    {
-      warning ("Unable to access %ld bytes of target "
-              "memory at 0x%lx, halting search.",
-              (long) search_buf_size, (long) start_addr);
-      return -1;
-    }
-
-  /* Perform the search.
-
-     The loop is kept simple by allocating [N + pattern-length - 1] bytes.
-     When we've scanned N bytes we copy the trailing bytes to the start and
-     read in another N bytes.  */
-
-  while (search_space_len >= pattern_len)
-    {
-      gdb_byte *found_ptr;
-      unsigned nr_search_bytes = (search_space_len < search_buf_size
-                                 ? search_space_len
-                                 : search_buf_size);
-
-      found_ptr = (gdb_byte *) memmem (search_buf, nr_search_bytes, pattern,
-                                      pattern_len);
-
-      if (found_ptr != NULL)
-       {
-         CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
-         *found_addrp = found_addr;
-         return 1;
-       }
-
-      /* Not found in this chunk, skip to next chunk.  */
-
-      /* Don't let search_space_len wrap here, it's unsigned.  */
-      if (search_space_len >= chunk_size)
-       search_space_len -= chunk_size;
-      else
-       search_space_len = 0;
-
-      if (search_space_len >= pattern_len)
-       {
-         unsigned keep_len = search_buf_size - chunk_size;
-         CORE_ADDR read_addr = start_addr + chunk_size + keep_len;
-         int nr_to_read;
-
-         /* Copy the trailing part of the previous iteration to the front
-            of the buffer for the next iteration.  */
-         memcpy (search_buf, search_buf + chunk_size, keep_len);
-
-         nr_to_read = (search_space_len - keep_len < chunk_size
-                       ? search_space_len - keep_len
-                       : chunk_size);
-
-         if (gdb_read_memory (read_addr, search_buf + keep_len,
-                              nr_to_read) != nr_to_read)
-           {
-             warning ("Unable to access %ld bytes of target memory "
-                      "at 0x%lx, halting search.",
-                      (long) nr_to_read, (long) read_addr);
-             return -1;
-           }
-
-         start_addr += chunk_size;
-       }
-    }
-
-  /* Not found.  */
-
-  return 0;
-}
-
 /* Handle qSearch:memory packets.  */
 
 static void
@@ -1130,23 +1145,14 @@ handle_search_memory (char *own_buf, int packet_len)
   CORE_ADDR search_space_len;
   gdb_byte *pattern;
   unsigned int pattern_len;
-  /* NOTE: also defined in find.c testcase.  */
-#define SEARCH_CHUNK_SIZE 16000
-  const unsigned chunk_size = SEARCH_CHUNK_SIZE;
-  /* Buffer to hold memory contents for searching.  */
-  gdb_byte *search_buf;
-  unsigned search_buf_size;
   int found;
   CORE_ADDR found_addr;
   int cmd_name_len = sizeof ("qSearch:memory:") - 1;
 
   pattern = (gdb_byte *) malloc (packet_len);
   if (pattern == NULL)
-    {
-      error ("Unable to allocate memory to perform the search");
-      strcpy (own_buf, "E00");
-      return;
-    }
+    error ("Unable to allocate memory to perform the search");
+
   if (decode_search_memory_packet (own_buf + cmd_name_len,
                                   packet_len - cmd_name_len,
                                   &start_addr, &search_space_len,
@@ -1154,29 +1160,15 @@ handle_search_memory (char *own_buf, int packet_len)
     {
       free (pattern);
       error ("Error in parsing qSearch:memory packet");
-      strcpy (own_buf, "E00");
-      return;
     }
 
-  search_buf_size = chunk_size + pattern_len - 1;
-
-  /* No point in trying to allocate a buffer larger than the search space.  */
-  if (search_space_len < search_buf_size)
-    search_buf_size = search_space_len;
-
-  search_buf = (gdb_byte *) malloc (search_buf_size);
-  if (search_buf == NULL)
+  auto read_memory = [] (CORE_ADDR addr, gdb_byte *result, size_t len)
     {
-      free (pattern);
-      error ("Unable to allocate memory to perform the search");
-      strcpy (own_buf, "E00");
-      return;
-    }
+      return gdb_read_memory (addr, result, len) == len;
+    };
 
-  found = handle_search_memory_1 (start_addr, search_space_len,
-                                 pattern, pattern_len,
-                                 search_buf, chunk_size, search_buf_size,
-                                 &found_addr);
+  found = simple_search_memory (read_memory, start_addr, search_space_len,
+                               pattern, pattern_len, &found_addr);
 
   if (found > 0)
     sprintf (own_buf, "1,%lx", (long) found_addr);
@@ -1185,7 +1177,6 @@ handle_search_memory (char *own_buf, int packet_len)
   else
     strcpy (own_buf, "E00");
 
-  free (search_buf);
   free (pattern);
 }
 
@@ -1389,6 +1380,16 @@ handle_monitor_command (char *mon, char *own_buf)
       remote_debug = 0;
       monitor_output ("Protocol debug output disabled.\n");
     }
+  else if (strcmp (mon, "set event-loop-debug 1") == 0)
+    {
+      debug_event_loop = debug_event_loop_kind::ALL;
+      monitor_output ("Event loop debug output enabled.\n");
+    }
+  else if (strcmp (mon, "set event-loop-debug 0") == 0)
+    {
+      debug_event_loop = debug_event_loop_kind::OFF;
+      monitor_output ("Event loop debug output disabled.\n");
+    }
   else if (startswith (mon, "set debug-format "))
     {
       std::string error_msg
@@ -1465,7 +1466,6 @@ handle_qxfer_exec_file (const char *annex,
                        gdb_byte *readbuf, const gdb_byte *writebuf,
                        ULONGEST offset, LONGEST len)
 {
-  char *file;
   ULONGEST pid;
   int total_len;
 
@@ -1489,7 +1489,7 @@ handle_qxfer_exec_file (const char *annex,
   if (pid <= 0)
     return -1;
 
-  file = the_target->pid_to_exec_file (pid);
+  const char *file = the_target->pid_to_exec_file (pid);
   if (file == NULL)
     return -1;
 
@@ -1553,7 +1553,8 @@ handle_qxfer_libraries (const char *annex,
 
   std::string document = "<library-list version=\"1.0\">\n";
 
-  for (const dll_info &dll : all_dlls)
+  process_info *proc = current_process ();
+  for (const dll_info &dll : proc->all_dlls)
     document += string_printf
       ("  <library name=\"%s\"><segment address=\"0x%s\"/></library>\n",
        dll.name.c_str (), paddress (dll.base_addr));
@@ -2158,6 +2159,27 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
   return (unsigned long long) crc;
 }
 
+/* Parse the qMemTags packet request into ADDR and LEN.  */
+
+static void
+parse_fetch_memtags_request (char *request, CORE_ADDR *addr, size_t *len,
+                            int *type)
+{
+  gdb_assert (startswith (request, "qMemTags:"));
+
+  const char *p = request + strlen ("qMemTags:");
+
+  /* Read address and length.  */
+  unsigned int length = 0;
+  p = decode_m_packet_params (p, addr, &length, ':');
+  *len = length;
+
+  /* Read the tag type.  */
+  ULONGEST tag_type = 0;
+  p = unpack_varlen_hex (p, &tag_type);
+  *type = (int) tag_type;
+}
+
 /* Add supported btrace packets to BUF.  */
 
 static void
@@ -2376,6 +2398,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
                     events.  */
                  report_no_resumed = true;
                }
+             else if (feature == "memory-tagging+")
+               {
+                 /* GDB supports memory tagging features.  */
+                 if (target_supports_memory_tagging ())
+                   cs.memory_tagging_feature = true;
+               }
              else
                {
                  /* Move the unknown features all together.  */
@@ -2493,6 +2521,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 
       strcat (own_buf, ";no-resumed+");
 
+      if (target_supports_memory_tagging ())
+       strcat (own_buf, ";memory-tagging+");
+
       /* Reinitialize components as needed for the new connection.  */
       hostio_handle_new_gdb_connection ();
       target_handle_new_gdb_connection ();
@@ -2685,6 +2716,31 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
   if (target_supports_tracepoints () && handle_tracepoint_query (own_buf))
     return;
 
+  /* Handle fetch memory tags packets.  */
+  if (startswith (own_buf, "qMemTags:")
+      && target_supports_memory_tagging ())
+    {
+      gdb::byte_vector tags;
+      CORE_ADDR addr = 0;
+      size_t len = 0;
+      int type = 0;
+
+      require_running_or_return (own_buf);
+
+      parse_fetch_memtags_request (own_buf, &addr, &len, &type);
+
+      bool ret = the_target->fetch_memtags (addr, len, tags, type);
+
+      if (ret)
+       ret = create_fetch_memtags_reply (own_buf, tags);
+
+      if (!ret)
+       write_enn (own_buf);
+
+      *new_packet_len_p = strlen (own_buf);
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -2899,7 +2955,7 @@ resume (struct thread_resume *actions, size_t num_actions)
        }
 
       if (cs.last_status.kind != TARGET_WAITKIND_EXITED
-          && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED
+         && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED
          && cs.last_status.kind != TARGET_WAITKIND_NO_RESUMED)
        current_thread->last_status = cs.last_status;
 
@@ -2912,13 +2968,13 @@ resume (struct thread_resume *actions, size_t num_actions)
       disable_async_io ();
 
       if (cs.last_status.kind == TARGET_WAITKIND_EXITED
-          || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
-        target_mourn_inferior (cs.last_ptid);
+         || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
+       target_mourn_inferior (cs.last_ptid);
     }
 }
 
-/* Attach to a new program.  Return 1 if successful, 0 if failure.  */
-static int
+/* Attach to a new program.  */
+static void
 handle_v_attach (char *own_buf)
 {
   client_state &cs = get_client_state ();
@@ -2931,7 +2987,7 @@ handle_v_attach (char *own_buf)
         some libraries are preloaded.  GDB will always poll the
         library list.  Avoids the "stopped by shared library event"
         notice on the GDB side.  */
-      dlls_changed = 0;
+      current_process ()->dlls_changed = false;
 
       if (non_stop)
        {
@@ -2942,18 +2998,13 @@ handle_v_attach (char *own_buf)
        }
       else
        prepare_resume_reply (own_buf, cs.last_ptid, &cs.last_status);
-
-      return 1;
     }
   else
-    {
-      write_enn (own_buf);
-      return 0;
-    }
+    write_enn (own_buf);
 }
 
-/* Run a new program.  Return 1 if successful, 0 if failure.  */
-static int
+/* Run a new program.  */
+static void
 handle_v_run (char *own_buf)
 {
   client_state &cs = get_client_state ();
@@ -3050,7 +3101,7 @@ handle_v_run (char *own_buf)
        {
          write_enn (own_buf);
          free_vector_argv (new_argv);
-         return 0;
+         return;
        }
     }
   else
@@ -3071,18 +3122,13 @@ handle_v_run (char *own_buf)
         query which is the main thread of the new inferior.  */
       if (non_stop)
        cs.general_thread = cs.last_ptid;
-
-      return 1;
     }
   else
-    {
-      write_enn (own_buf);
-      return 0;
-    }
+    write_enn (own_buf);
 }
 
-/* Kill process.  Return 1 if successful, 0 if failure.  */
-static int
+/* Kill process.  */
+static void
 handle_v_kill (char *own_buf)
 {
   client_state &cs = get_client_state ();
@@ -3102,13 +3148,9 @@ handle_v_kill (char *own_buf)
       cs.last_ptid = ptid_t (pid);
       discard_queued_stop_replies (cs.last_ptid);
       write_ok (own_buf);
-      return 1;
     }
   else
-    {
-      write_enn (own_buf);
-      return 0;
-    }
+    write_enn (own_buf);
 }
 
 /* Handle all of the extended 'v' packets.  */
@@ -3413,7 +3455,7 @@ static void
 gdbserver_version (void)
 {
   printf ("GNU gdbserver %s%s\n"
-         "Copyright (C) 2020 Free Software Foundation, Inc.\n"
+         "Copyright (C) 2021 Free Software Foundation, Inc.\n"
          "gdbserver is free software, covered by the "
          "GNU General Public License.\n"
          "This gdbserver was configured as \"%s\"\n",
@@ -3468,10 +3510,11 @@ gdbserver_usage (FILE *stream)
           "                            none\n"
           "                            timestamp\n"
           "  --remote-debug        Enable remote protocol debugging output.\n"
+          "  --event-loop-debug    Enable event loop debugging output.\n"
           "  --disable-packet=OPT1[,OPT2,...]\n"
           "                        Disable support for RSP packets or features.\n"
           "                          Options:\n"
-          "                            vCont, Tthread, qC, qfThreadInfo and \n"
+          "                            vCont, T, Tthread, qC, qfThreadInfo and \n"
           "                            threads (disable all threading packets).\n"
           "\n"
           "For more information, consult the GDB manual (available as on-line \n"
@@ -3489,7 +3532,8 @@ gdbserver_show_disableable (FILE *stream)
           "  qfThreadInfo\tThread listing\n"
           "  Tthread     \tPassing the thread specifier in the "
           "T stop reply packet\n"
-          "  threads     \tAll of the above\n");
+          "  threads     \tAll of the above\n"
+          "  T           \tAll 'T' packets\n");
 }
 
 /* Start up the event loop.  This is the entry point to the event
@@ -3594,6 +3638,81 @@ detach_or_kill_for_exit_cleanup ()
     }
 }
 
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+static void
+test_memory_tagging_functions (void)
+{
+  /* Setup testing.  */
+  gdb::char_vector packet;
+  gdb::byte_vector tags, bv;
+  std::string expected;
+  packet.resize (32000);
+  CORE_ADDR addr;
+  size_t len;
+  int type;
+
+  /* Test parsing a qMemTags request.  */
+
+  /* Valid request, addr, len and type updated.  */
+  addr = 0xff;
+  len = 255;
+  type = 255;
+  strcpy (packet.data (), "qMemTags:0,0:0");
+  parse_fetch_memtags_request (packet.data (), &addr, &len, &type);
+  SELF_CHECK (addr == 0 && len == 0 && type == 0);
+
+  /* Valid request, addr, len and type updated.  */
+  addr = 0;
+  len = 0;
+  type = 0;
+  strcpy (packet.data (), "qMemTags:deadbeef,ff:5");
+  parse_fetch_memtags_request (packet.data (), &addr, &len, &type);
+  SELF_CHECK (addr == 0xdeadbeef && len == 255 && type == 5);
+
+  /* Test creating a qMemTags reply.  */
+
+  /* Non-empty tag data.  */
+  bv.resize (0);
+
+  for (int i = 0; i < 5; i++)
+    bv.push_back (i);
+
+  expected = "m0001020304";
+  SELF_CHECK (create_fetch_memtags_reply (packet.data (), bv) == true);
+  SELF_CHECK (strcmp (packet.data (), expected.c_str ()) == 0);
+
+  /* Test parsing a QMemTags request.  */
+
+  /* Valid request and empty tag data: addr, len, type and tags updated.  */
+  addr = 0xff;
+  len = 255;
+  type = 255;
+  tags.resize (5);
+  strcpy (packet.data (), "QMemTags:0,0:0:");
+  SELF_CHECK (parse_store_memtags_request (packet.data (),
+                                          &addr, &len, tags, &type) == true);
+  SELF_CHECK (addr == 0 && len == 0 && type == 0 && tags.size () == 0);
+
+  /* Valid request and non-empty tag data: addr, len, type
+     and tags updated.  */
+  addr = 0;
+  len = 0;
+  type = 0;
+  tags.resize (0);
+  strcpy (packet.data (),
+         "QMemTags:deadbeef,ff:5:0001020304");
+  SELF_CHECK (parse_store_memtags_request (packet.data (), &addr, &len, tags,
+                                          &type) == true);
+  SELF_CHECK (addr == 0xdeadbeef && len == 255 && type == 5
+             && tags.size () == 5);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
 /* Main function.  This is called by the real "main" function,
    wrapped in a TRY_CATCH that handles any uncaught exceptions.  */
 
@@ -3611,6 +3730,9 @@ captured_main (int argc, char *argv[])
   bool selftest = false;
 #if GDB_SELF_TEST
   std::vector<const char *> selftest_filters;
+
+  selftests::register_test ("remote_memory_tagging",
+                           selftests::test_memory_tagging_functions);
 #endif
 
   current_directory = getcwd (NULL, 0);
@@ -3683,6 +3805,8 @@ captured_main (int argc, char *argv[])
        }
       else if (strcmp (*next_arg, "--remote-debug") == 0)
        remote_debug = 1;
+      else if (strcmp (*next_arg, "--event-loop-debug") == 0)
+       debug_event_loop = debug_event_loop_kind::ALL;
       else if (startswith (*next_arg, "--debug-file="))
        debug_set_output ((*next_arg) + sizeof ("--debug-file=") -1);
       else if (strcmp (*next_arg, "--disable-packet") == 0)
@@ -3875,7 +3999,8 @@ captured_main (int argc, char *argv[])
   /* Don't report shared library events on the initial connection,
      even if some libraries are preloaded.  Avoids the "stopped by
      shared library event" notice on gdb side.  */
-  dlls_changed = 0;
+  if (current_thread != nullptr)
+    current_process ()->dlls_changed = false;
 
   if (cs.last_status.kind == TARGET_WAITKIND_EXITED
       || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
@@ -3899,6 +4024,7 @@ captured_main (int argc, char *argv[])
       cs.swbreak_feature = 0;
       cs.hwbreak_feature = 0;
       cs.vCont_supported = 0;
+      cs.memory_tagging_feature = false;
 
       remote_open (port);
 
@@ -3918,11 +4044,11 @@ captured_main (int argc, char *argv[])
              - If --once was specified, we're done.
 
              - If not in extended-remote mode, and we're no longer
-               debugging anything, simply exit: GDB has disconnected
-               after processing the last process exit.
+               debugging anything, simply exit: GDB has disconnected
+               after processing the last process exit.
 
              - Otherwise, close the connection and reopen it at the
-               top of the loop.  */
+               top of the loop.  */
          if (run_once || (!extended_protocol && !target_running ()))
            throw_quit ("Quit");