From 546b77fe78bb366bbec3c708ac371e2f553bbdae Mon Sep 17 00:00:00 2001 From: Luis Machado Date: Mon, 15 Jun 2020 15:34:06 -0300 Subject: GDBserver remote packet support for memory tagging This patch adds the generic remote bits to gdbserver so it can check for memory tagging support and handle fetch tags and store tags requests. gdbserver/ChangeLog: 2021-03-24 Luis Machado * remote-utils.cc (decode_m_packet_params): Renamed from ... (decode_m_packet): ... this, which now calls decode_m_packet_params. Make char * param/return const char *. (decode_M_packet): Use decode_m_packet_params and make char * param const char *. * remote-utils.h (decode_m_packet_params): New prototype. (decode_m_packet): Constify char pointers. (decode_M_packet): Likewise. * server.cc (create_fetch_memtags_reply) (parse_store_memtags_request): New functions. (handle_general_set): Handle the QMemTags packet. (parse_fetch_memtags_request): New function. (handle_query): Handle the qMemTags packet and advertise memory tagging support. (captured_main): Initialize memory tagging flag. * server.h (struct client_state): Initialize memory tagging flag. * target.cc (process_stratum_target::supports_memory_tagging) (process_stratum_target::fetch_memtags) (process_stratum_target::store_memtags): New methods. * target.h: Include gdbsupport/byte-vector.h. (class process_stratum_target) : New class virtual methods. (target_supports_memory_tagging): Define. --- gdbserver/ChangeLog | 27 +++++++++ gdbserver/remote-utils.cc | 42 +++++++------- gdbserver/remote-utils.h | 12 +++- gdbserver/server.cc | 140 ++++++++++++++++++++++++++++++++++++++++++++++ gdbserver/server.h | 3 + gdbserver/target.cc | 20 +++++++ gdbserver/target.h | 21 +++++++ 7 files changed, 240 insertions(+), 25 deletions(-) diff --git a/gdbserver/ChangeLog b/gdbserver/ChangeLog index d870154..f055566 100644 --- a/gdbserver/ChangeLog +++ b/gdbserver/ChangeLog @@ -1,3 +1,30 @@ +2021-03-24 Luis Machado + + * remote-utils.cc (decode_m_packet_params): Renamed from ... + (decode_m_packet): ... this, which now calls decode_m_packet_params. + Make char * param/return const char *. + (decode_M_packet): Use decode_m_packet_params and make char * param + const char *. + * remote-utils.h (decode_m_packet_params): New prototype. + (decode_m_packet): Constify char pointers. + (decode_M_packet): Likewise. + * server.cc (create_fetch_memtags_reply) + (parse_store_memtags_request): New + functions. + (handle_general_set): Handle the QMemTags packet. + (parse_fetch_memtags_request): New function. + (handle_query): Handle the qMemTags packet and advertise memory + tagging support. + (captured_main): Initialize memory tagging flag. + * server.h (struct client_state): Initialize memory tagging flag. + * target.cc (process_stratum_target::supports_memory_tagging) + (process_stratum_target::fetch_memtags) + (process_stratum_target::store_memtags): New methods. + * target.h: Include gdbsupport/byte-vector.h. + (class process_stratum_target) + : New class virtual methods. + (target_supports_memory_tagging): Define. + 2021-03-22 Tankut Baris Aktemur * inferiors.h (struct process_info) : New diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc index 509b813..198a75a 100644 --- a/gdbserver/remote-utils.cc +++ b/gdbserver/remote-utils.cc @@ -1308,10 +1308,13 @@ prepare_resume_reply (char *buf, ptid_t ptid, } } -void -decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr) +/* See remote-utils.h. */ + +const char * +decode_m_packet_params (const char *from, CORE_ADDR *mem_addr_ptr, + unsigned int *len_ptr, const char end_marker) { - int i = 0, j = 0; + int i = 0; char ch; *mem_addr_ptr = *len_ptr = 0; @@ -1321,39 +1324,32 @@ decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr) *mem_addr_ptr |= fromhex (ch) & 0x0f; } - for (j = 0; j < 4; j++) + while ((ch = from[i++]) != end_marker) { - if ((ch = from[i++]) == 0) - break; *len_ptr = *len_ptr << 4; *len_ptr |= fromhex (ch) & 0x0f; } + + return from + i; } void -decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr, - unsigned char **to_p) +decode_m_packet (const char *from, CORE_ADDR *mem_addr_ptr, + unsigned int *len_ptr) { - int i = 0; - char ch; - *mem_addr_ptr = *len_ptr = 0; - - while ((ch = from[i++]) != ',') - { - *mem_addr_ptr = *mem_addr_ptr << 4; - *mem_addr_ptr |= fromhex (ch) & 0x0f; - } + decode_m_packet_params (from, mem_addr_ptr, len_ptr, '\0'); +} - while ((ch = from[i++]) != ':') - { - *len_ptr = *len_ptr << 4; - *len_ptr |= fromhex (ch) & 0x0f; - } +void +decode_M_packet (const char *from, CORE_ADDR *mem_addr_ptr, + unsigned int *len_ptr, unsigned char **to_p) +{ + from = decode_m_packet_params (from, mem_addr_ptr, len_ptr, ':'); if (*to_p == NULL) *to_p = (unsigned char *) xmalloc (*len_ptr); - hex2bin (&from[i++], *to_p, *len_ptr); + hex2bin (from, *to_p, *len_ptr); } int diff --git a/gdbserver/remote-utils.h b/gdbserver/remote-utils.h index 5a8e764..25074bc 100644 --- a/gdbserver/remote-utils.h +++ b/gdbserver/remote-utils.h @@ -45,9 +45,17 @@ void prepare_resume_reply (char *buf, ptid_t ptid, const char *decode_address_to_semicolon (CORE_ADDR *addrp, const char *start); void decode_address (CORE_ADDR *addrp, const char *start, int len); -void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr, + +/* Given an input string FROM, decode MEM_ADDR_PTR, a memory address in hex + form, and LEN_PTR, a length argument in hex form, from the pattern + ",", with END_MARKER being an end marker + character. */ +const char *decode_m_packet_params (const char *from, CORE_ADDR *mem_addr_ptr, + unsigned int *len_ptr, + const char end_marker); +void decode_m_packet (const char *from, CORE_ADDR * mem_addr_ptr, unsigned int *len_ptr); -void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr, +void decode_M_packet (const char *from, CORE_ADDR * mem_addr_ptr, unsigned int *len_ptr, unsigned char **to_p); int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr, unsigned int *len_ptr, unsigned char **to_p); diff --git a/gdbserver/server.cc b/gdbserver/server.cc index ea731d5..5887133 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -556,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 @@ -912,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); + + int ret = parse_store_memtags_request (own_buf, &addr, &len, tags, + &type); + + if (ret == 0) + 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; @@ -2076,6 +2160,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 @@ -2294,6 +2399,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. */ @@ -2411,6 +2522,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 (); @@ -2603,6 +2717,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); + + int 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; @@ -3822,6 +3961,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); diff --git a/gdbserver/server.h b/gdbserver/server.h index 416544c..3e28073 100644 --- a/gdbserver/server.h +++ b/gdbserver/server.h @@ -190,6 +190,9 @@ struct client_state int current_traceframe = -1; + /* If true, memory tagging features are supported. */ + bool memory_tagging_feature = false; + }; client_state &get_client_state (); diff --git a/gdbserver/target.cc b/gdbserver/target.cc index 4c6f775..1f21597 100644 --- a/gdbserver/target.cc +++ b/gdbserver/target.cc @@ -464,6 +464,26 @@ process_stratum_target::supports_read_offsets () return false; } +bool +process_stratum_target::supports_memory_tagging () +{ + return false; +} + +bool +process_stratum_target::fetch_memtags (CORE_ADDR address, size_t len, + gdb::byte_vector &tags, int type) +{ + gdb_assert_not_reached ("target op fetch_memtags not supported"); +} + +bool +process_stratum_target::store_memtags (CORE_ADDR address, size_t len, + const gdb::byte_vector &tags, int type) +{ + gdb_assert_not_reached ("target op store_memtags not supported"); +} + int process_stratum_target::read_offsets (CORE_ADDR *text, CORE_ADDR *data) { diff --git a/gdbserver/target.h b/gdbserver/target.h index 336ee5a..2831a6c 100644 --- a/gdbserver/target.h +++ b/gdbserver/target.h @@ -30,6 +30,7 @@ #include "gdbsupport/array-view.h" #include "gdbsupport/btrace-common.h" #include +#include "gdbsupport/byte-vector.h" struct emit_ops; struct buffer; @@ -499,6 +500,23 @@ public: /* Return tdesc index for IPA. */ virtual int get_ipa_tdesc_idx (); + + /* Returns true if the target supports memory tagging facilities. */ + virtual bool supports_memory_tagging (); + + /* Return the allocated memory tags of type TYPE associated with + [ADDRESS, ADDRESS + LEN) in TAGS. + + Returns true if successful and false otherwise. */ + virtual bool fetch_memtags (CORE_ADDR address, size_t len, + gdb::byte_vector &tags, int type); + + /* Write the allocation tags of type TYPE contained in TAGS to the + memory range [ADDRESS, ADDRESS + LEN). + + Returns true if successful and false otherwise. */ + virtual bool store_memtags (CORE_ADDR address, size_t len, + const gdb::byte_vector &tags, int type); }; extern process_stratum_target *the_target; @@ -525,6 +543,9 @@ int kill_inferior (process_info *proc); #define target_supports_exec_events() \ the_target->supports_exec_events () +#define target_supports_memory_tagging() \ + the_target->supports_memory_tagging () + #define target_handle_new_gdb_connection() \ the_target->handle_new_gdb_connection () -- cgit v1.1