@@ -208,6 +208,50 @@ find_register_by_number (const struct target_desc *tdesc, int n)
#ifndef IN_PROCESS_AGENT
+static gdb::array_view<gdb_byte> register_data (const struct regcache *regcache,
+ int n);
+
+/* See regcache.h. */
+
+void
+register_to_string (struct regcache *regcache, int regnum, char *buf)
+{
+ if (regcache->register_status[regnum] == REG_VALID)
+ {
+ gdb::array_view<gdb_byte> value = register_data (regcache, regnum);
+
+ bin2hex (value.data (), buf, value.size ());
+ buf[value.size () * 2] = '\0';
+ }
+ else
+ {
+ int len = regcache->register_size (regnum) * 2;
+
+ memset (buf, 'x', len);
+ buf[len] = '\0';
+ }
+}
+
+/* See regcache.h. */
+
+void
+register_from_string (struct regcache *regcache, int regnum, char *buf)
+{
+ int len = strlen (buf);
+ gdb::array_view<gdb_byte> value = register_data (regcache, regnum);
+ int expected_len = value.size () * 2;
+
+ if (len != expected_len)
+ {
+ warning ("Wrong sized packet for register %d (expected %d bytes, got %d)",
+ regnum, expected_len, len);
+ if (len > expected_len)
+ len = expected_len;
+ }
+
+ hex2bin (buf, value.data (), len / 2);
+}
+
void
registers_to_string (struct regcache *regcache, char *buf)
{
@@ -96,6 +96,15 @@ void regcache_invalidate (void);
void regcache_release (void);
+/* Save contents of register REGNUM to BUF as an hexadecimal string. */
+
+void register_to_string (struct regcache *regcache, int regnum, char *buf);
+
+/* Set contents of register REGNUM from BUF, interpreted as an hexadecimal
+ string. */
+
+void register_from_string (struct regcache *regcache, int regnum, char *buf);
+
/* Convert all registers to a string in the currently specified remote
format. */
@@ -4712,6 +4712,81 @@ process_serial_event (void)
}
}
break;
+ case 'p':
+ {
+ require_running_or_break (cs.own_buf);
+ if (cs.current_traceframe >= 0)
+ {
+ write_enn (cs.own_buf);
+ break;
+ }
+ if (!set_desired_thread ())
+ {
+ write_enn (cs.own_buf);
+ break;
+ }
+
+ int i = 1, regnum = 0;
+ char c;
+ while ((c = cs.own_buf[i++]) != '\0')
+ {
+ regnum = regnum << 4;
+ regnum |= fromhex (c) & 0x0f;
+ }
+
+ struct regcache *regcache = get_thread_regcache (current_thread, true);
+
+ if (regnum < 0 || regnum >= regcache->tdesc->reg_defs.size ())
+ {
+ write_enn (cs.own_buf);
+ break;
+ }
+
+ fetch_inferior_registers (regcache, regnum);
+ register_to_string (regcache, regnum, cs.own_buf);
+ }
+ break;
+ case 'P':
+ {
+ require_running_or_break (cs.own_buf);
+ if (cs.current_traceframe >= 0)
+ {
+ write_enn (cs.own_buf);
+ break;
+ }
+ if (!set_desired_thread ())
+ {
+ write_enn (cs.own_buf);
+ break;
+ }
+ if (strchr (cs.own_buf, '=') == nullptr)
+ {
+ write_enn (cs.own_buf);
+ break;
+ }
+
+ int i = 1, regnum = 0;
+ char c;
+ while ((c = cs.own_buf[i++]) != '=')
+ {
+ regnum = regnum << 4;
+ regnum |= fromhex (c) & 0x0f;
+ }
+
+ struct regcache *regcache = get_thread_regcache (current_thread, true);
+
+ if (regnum < 0 || regnum >= regcache->tdesc->reg_defs.size ())
+ {
+ write_enn (cs.own_buf);
+ break;
+ }
+
+ register_from_string (regcache, regnum, &cs.own_buf[i]);
+ /* FIXME: Why doesn't the G packet need this as well? */
+ store_inferior_registers (regcache, regnum);
+ write_ok (cs.own_buf);
+ }
+ break;
case 'm':
{
require_running_or_break (cs.own_buf);