#ifndef IN_PROCESS_AGENT
+static gdb::array_view<gdb_byte> register_data (const struct regcache *regcache,
+ int n);
+
+/* See regcache.h. */
+
+bool
+register_from_string (struct regcache *regcache, int regnum,
+ gdb::array_view<const char> buf)
+{
+ gdb::array_view<gdb_byte> value = register_data (regcache, regnum);
+ int expected_len = value.size () * 2;
+
+ if (buf.size () != expected_len)
+ {
+ warning (_("Wrong sized packet for register %d (expected %d bytes, got %zu)"),
+ regnum, expected_len, buf.size ());
+ return false;
+ }
+
+ hex2bin (buf.data (), value.data (), buf.size () / 2);
+
+ return true;
+}
+
void
registers_to_string (struct regcache *regcache, char *buf)
{
*packet = dataptr;
}
+static bool
+can_access_registers (client_state &cs)
+{
+ if (!target_running () || cs.current_traceframe >= 0
+ || !set_desired_thread ())
+ {
+ write_enn (cs.own_buf);
+ return false;
+ }
+
+ return true;
+}
+
/* Event loop callback that handles a serial event. The first byte in
the serial buffer gets us here. We expect characters to arrive at
a brisk pace, so we read the rest of the packet with a blocking
}
break;
case 'G':
- require_running_or_break (cs.own_buf);
- if (cs.current_traceframe >= 0)
- write_enn (cs.own_buf);
- else
- {
- struct regcache *regcache;
+ {
+ if (!can_access_registers (cs))
+ break;
- if (!set_desired_thread ())
+ regcache *regcache = get_thread_regcache (current_thread, 1);
+ registers_from_string (regcache, &cs.own_buf[1]);
+ write_ok (cs.own_buf);
+ }
+ break;
+ case 'p':
+ {
+ if (!can_access_registers (cs))
+ 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);
- else
- {
- regcache = get_thread_regcache (current_thread);
- registers_from_string (regcache, &cs.own_buf[1]);
- write_ok (cs.own_buf);
- }
- }
+ break;
+ }
+
+ fetch_inferior_registers (regcache, regnum);
+ collect_register_as_string (regcache, regnum, cs.own_buf);
+ }
+ break;
+ case 'P':
+ {
+ if (!can_access_registers (cs))
+ 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;
+ }
+
+ len = strlen (&cs.own_buf[i]);
+ bool ret = register_from_string (regcache, regnum,
+ gdb::make_array_view (&cs.own_buf[i],
+ len));
+ if (!ret)
+ {
+ write_enn (cs.own_buf);
+ break;
+ }
+
+ /* FIXME: Why doesn't the G packet need this as well? */
+ store_inferior_registers (regcache, regnum);
+ write_ok (cs.own_buf);
+ }
break;
case 'm':
{