/* 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.
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;
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
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;
}
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;
gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, LONGEST len)
{
- char *file;
ULONGEST pid;
int total_len;
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;
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));
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
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. */
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 ();
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;
}
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;
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 ();
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)
{
}
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 ();
{
write_enn (own_buf);
free_vector_argv (new_argv);
- return 0;
+ return;
}
}
else
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 ();
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. */
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",
" --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"
" 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
}
}
+#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. */
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);
/* 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)
cs.swbreak_feature = 0;
cs.hwbreak_feature = 0;
cs.vCont_supported = 0;
+ cs.memory_tagging_feature = false;
remote_open (port);
- 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");