+ ULONGEST addr;
+ char *p;
+
+ event->ptid = null_ptid;
+ event->ws.kind = TARGET_WAITKIND_IGNORE;
+ event->ws.value.integer = 0;
+ event->solibs_changed = 0;
+ event->replay_event = 0;
+ event->stopped_by_watchpoint_p = 0;
+ event->regcache = NULL;
+ event->core = -1;
+
+ switch (buf[0])
+ {
+ case 'T': /* Status with PC, SP, FP, ... */
+ /* Expedited reply, containing Signal, {regno, reg} repeat. */
+ /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
+ ss = signal number
+ n... = register number
+ r... = register contents
+ */
+
+ p = &buf[3]; /* after Txx */
+ while (*p)
+ {
+ char *p1;
+ char *p_temp;
+ int fieldsize;
+ LONGEST pnum = 0;
+
+ /* If the packet contains a register number, save it in
+ pnum and set p1 to point to the character following it.
+ Otherwise p1 points to p. */
+
+ /* If this packet is an awatch packet, don't parse the 'a'
+ as a register number. */
+
+ if (strncmp (p, "awatch", strlen("awatch")) != 0
+ && strncmp (p, "core", strlen ("core") != 0))
+ {
+ /* Read the ``P'' register number. */
+ pnum = strtol (p, &p_temp, 16);
+ p1 = p_temp;
+ }
+ else
+ p1 = p;
+
+ if (p1 == p) /* No register number present here. */
+ {
+ p1 = strchr (p, ':');
+ if (p1 == NULL)
+ error (_("Malformed packet(a) (missing colon): %s\n\
+Packet: '%s'\n"),
+ p, buf);
+ if (strncmp (p, "thread", p1 - p) == 0)
+ event->ptid = read_ptid (++p1, &p);
+ else if ((strncmp (p, "watch", p1 - p) == 0)
+ || (strncmp (p, "rwatch", p1 - p) == 0)
+ || (strncmp (p, "awatch", p1 - p) == 0))
+ {
+ event->stopped_by_watchpoint_p = 1;
+ p = unpack_varlen_hex (++p1, &addr);
+ event->watch_data_address = (CORE_ADDR) addr;
+ }
+ else if (strncmp (p, "library", p1 - p) == 0)
+ {
+ p1++;
+ p_temp = p1;
+ while (*p_temp && *p_temp != ';')
+ p_temp++;
+
+ event->solibs_changed = 1;
+ p = p_temp;
+ }
+ else if (strncmp (p, "replaylog", p1 - p) == 0)
+ {
+ /* NO_HISTORY event.
+ p1 will indicate "begin" or "end", but
+ it makes no difference for now, so ignore it. */
+ event->replay_event = 1;
+ p_temp = strchr (p1 + 1, ';');
+ if (p_temp)
+ p = p_temp;
+ }
+ else if (strncmp (p, "core", p1 - p) == 0)
+ {
+ ULONGEST c;
+ p = unpack_varlen_hex (++p1, &c);
+ event->core = c;
+ }
+ else
+ {
+ /* Silently skip unknown optional info. */
+ p_temp = strchr (p1 + 1, ';');
+ if (p_temp)
+ p = p_temp;
+ }
+ }
+ else
+ {
+ struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
+ cached_reg_t cached_reg;
+
+ p = p1;
+
+ if (*p != ':')
+ error (_("Malformed packet(b) (missing colon): %s\n\
+Packet: '%s'\n"),
+ p, buf);
+ ++p;
+
+ if (reg == NULL)
+ error (_("Remote sent bad register number %s: %s\n\
+Packet: '%s'\n"),
+ phex_nz (pnum, 0), p, buf);
+
+ cached_reg.num = reg->regnum;
+
+ fieldsize = hex2bin (p, cached_reg.data,
+ register_size (target_gdbarch,
+ reg->regnum));
+ p += 2 * fieldsize;
+ if (fieldsize < register_size (target_gdbarch,
+ reg->regnum))
+ warning (_("Remote reply is too short: %s"), buf);
+
+ VEC_safe_push (cached_reg_t, event->regcache, &cached_reg);
+ }
+
+ if (*p != ';')
+ error (_("Remote register badly formatted: %s\nhere: %s"),
+ buf, p);
+ ++p;
+ }
+ /* fall through */
+ case 'S': /* Old style status, just signal only. */
+ if (event->solibs_changed)
+ event->ws.kind = TARGET_WAITKIND_LOADED;
+ else if (event->replay_event)
+ event->ws.kind = TARGET_WAITKIND_NO_HISTORY;
+ else
+ {
+ event->ws.kind = TARGET_WAITKIND_STOPPED;
+ event->ws.value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+ }
+ break;
+ case 'W': /* Target exited. */
+ case 'X':
+ {
+ char *p;
+ int pid;
+ ULONGEST value;
+
+ /* GDB used to accept only 2 hex chars here. Stubs should
+ only send more if they detect GDB supports multi-process
+ support. */
+ p = unpack_varlen_hex (&buf[1], &value);
+
+ if (buf[0] == 'W')
+ {
+ /* The remote process exited. */
+ event->ws.kind = TARGET_WAITKIND_EXITED;
+ event->ws.value.integer = value;
+ }
+ else
+ {
+ /* The remote process exited with a signal. */
+ event->ws.kind = TARGET_WAITKIND_SIGNALLED;
+ event->ws.value.sig = (enum target_signal) value;
+ }
+
+ /* If no process is specified, assume inferior_ptid. */
+ pid = ptid_get_pid (inferior_ptid);
+ if (*p == '\0')
+ ;
+ else if (*p == ';')
+ {
+ p++;
+
+ if (p == '\0')
+ ;
+ else if (strncmp (p,
+ "process:", sizeof ("process:") - 1) == 0)
+ {
+ ULONGEST upid;
+ p += sizeof ("process:") - 1;
+ unpack_varlen_hex (p, &upid);
+ pid = upid;
+ }
+ else
+ error (_("unknown stop reply packet: %s"), buf);
+ }
+ else
+ error (_("unknown stop reply packet: %s"), buf);
+ event->ptid = pid_to_ptid (pid);
+ }
+ break;
+ }
+
+ if (non_stop && ptid_equal (event->ptid, null_ptid))
+ error (_("No process or thread specified in stop reply: %s"), buf);
+}
+
+/* When the stub wants to tell GDB about a new stop reply, it sends a
+ stop notification (%Stop). Those can come it at any time, hence,
+ we have to make sure that any pending putpkt/getpkt sequence we're
+ making is finished, before querying the stub for more events with
+ vStopped. E.g., if we started a vStopped sequence immediatelly
+ upon receiving the %Stop notification, something like this could
+ happen:
+
+ 1.1) --> Hg 1
+ 1.2) <-- OK
+ 1.3) --> g
+ 1.4) <-- %Stop
+ 1.5) --> vStopped
+ 1.6) <-- (registers reply to step #1.3)
+
+ Obviously, the reply in step #1.6 would be unexpected to a vStopped
+ query.
+
+ To solve this, whenever we parse a %Stop notification sucessfully,
+ we mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN, and carry on
+ doing whatever we were doing:
+
+ 2.1) --> Hg 1
+ 2.2) <-- OK
+ 2.3) --> g
+ 2.4) <-- %Stop
+ <GDB marks the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
+ 2.5) <-- (registers reply to step #2.3)
+
+ Eventualy after step #2.5, we return to the event loop, which
+ notices there's an event on the
+ REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN event and calls the
+ associated callback --- the function below. At this point, we're
+ always safe to start a vStopped sequence. :
+
+ 2.6) --> vStopped
+ 2.7) <-- T05 thread:2
+ 2.8) --> vStopped
+ 2.9) --> OK
+*/
+
+static void
+remote_get_pending_stop_replies (void)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ if (pending_stop_reply)
+ {
+ /* acknowledge */
+ putpkt ("vStopped");
+
+ /* Now we can rely on it. */
+ push_stop_reply (pending_stop_reply);
+ pending_stop_reply = NULL;
+
+ while (1)
+ {
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") == 0)
+ break;
+ else
+ {
+ struct cleanup *old_chain;
+ struct stop_reply *stop_reply = stop_reply_xmalloc ();
+
+ old_chain = make_cleanup (do_stop_reply_xfree, stop_reply);
+ remote_parse_stop_reply (rs->buf, stop_reply);
+
+ /* acknowledge */
+ putpkt ("vStopped");
+
+ if (stop_reply->ws.kind != TARGET_WAITKIND_IGNORE)
+ {
+ /* Now we can rely on it. */
+ discard_cleanups (old_chain);
+ push_stop_reply (stop_reply);
+ }
+ else
+ /* We got an unknown stop reply. */
+ do_cleanups (old_chain);
+ }
+ }
+ }
+}
+
+
+/* Called when it is decided that STOP_REPLY holds the info of the
+ event that is to be returned to the core. This function always
+ destroys STOP_REPLY. */
+
+static ptid_t
+process_stop_reply (struct stop_reply *stop_reply,
+ struct target_waitstatus *status)
+{
+ ptid_t ptid;
+ struct thread_info *info;
+
+ *status = stop_reply->ws;
+ ptid = stop_reply->ptid;
+
+ /* If no thread/process was reported by the stub, assume the current
+ inferior. */
+ if (ptid_equal (ptid, null_ptid))
+ ptid = inferior_ptid;
+
+ if (status->kind != TARGET_WAITKIND_EXITED
+ && status->kind != TARGET_WAITKIND_SIGNALLED)
+ {
+ /* Expedited registers. */
+ if (stop_reply->regcache)
+ {
+ struct regcache *regcache
+ = get_thread_arch_regcache (ptid, target_gdbarch);
+ cached_reg_t *reg;
+ int ix;
+
+ for (ix = 0;
+ VEC_iterate(cached_reg_t, stop_reply->regcache, ix, reg);
+ ix++)
+ regcache_raw_supply (regcache, reg->num, reg->data);
+ VEC_free (cached_reg_t, stop_reply->regcache);
+ }
+
+ remote_stopped_by_watchpoint_p = stop_reply->stopped_by_watchpoint_p;
+ remote_watch_data_address = stop_reply->watch_data_address;
+
+ remote_notice_new_inferior (ptid, 0);
+ demand_private_info (ptid)->core = stop_reply->core;
+ }
+
+ stop_reply_xfree (stop_reply);
+ return ptid;
+}
+
+/* The non-stop mode version of target_wait. */
+
+static ptid_t
+remote_wait_ns (ptid_t ptid, struct target_waitstatus *status, int options)
+{
+ struct remote_state *rs = get_remote_state ();
+ struct stop_reply *stop_reply;
+ int ret;
+
+ /* If in non-stop mode, get out of getpkt even if a
+ notification is received. */
+
+ ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size,
+ 0 /* forever */);
+ while (1)
+ {
+ if (ret != -1)
+ switch (rs->buf[0])
+ {
+ case 'E': /* Error of some sort. */
+ /* We're out of sync with the target now. Did it continue
+ or not? We can't tell which thread it was in non-stop,
+ so just ignore this. */
+ warning (_("Remote failure reply: %s"), rs->buf);
+ break;
+ case 'O': /* Console output. */
+ remote_console_output (rs->buf + 1);
+ break;
+ default:
+ warning (_("Invalid remote reply: %s"), rs->buf);
+ break;
+ }
+
+ /* Acknowledge a pending stop reply that may have arrived in the
+ mean time. */
+ if (pending_stop_reply != NULL)
+ remote_get_pending_stop_replies ();
+
+ /* If indeed we noticed a stop reply, we're done. */
+ stop_reply = queued_stop_reply (ptid);
+ if (stop_reply != NULL)
+ return process_stop_reply (stop_reply, status);
+
+ /* Still no event. If we're just polling for an event, then
+ return to the event loop. */
+ if (options & TARGET_WNOHANG)
+ {
+ status->kind = TARGET_WAITKIND_IGNORE;
+ return minus_one_ptid;
+ }
+
+ /* Otherwise do a blocking wait. */
+ ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size,
+ 1 /* forever */);
+ }
+}
+
+/* Wait until the remote machine stops, then return, storing status in
+ STATUS just as `wait' would. */
+
+static ptid_t
+remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options)
+{
+ struct remote_state *rs = get_remote_state ();
+ ptid_t event_ptid = null_ptid;
+ char *buf;
+ struct stop_reply *stop_reply;
+
+ again:
+
+ status->kind = TARGET_WAITKIND_IGNORE;
+ status->value.integer = 0;
+
+ stop_reply = queued_stop_reply (ptid);
+ if (stop_reply != NULL)
+ return process_stop_reply (stop_reply, status);
+
+ if (rs->cached_wait_status)
+ /* Use the cached wait status, but only once. */
+ rs->cached_wait_status = 0;
+ else
+ {
+ int ret;
+
+ if (!target_is_async_p ())
+ {
+ ofunc = signal (SIGINT, remote_interrupt);
+ /* If the user hit C-c before this packet, or between packets,
+ pretend that it was hit right here. */
+ if (quit_flag)
+ {
+ quit_flag = 0;
+ remote_interrupt (SIGINT);
+ }
+ }
+
+ /* FIXME: cagney/1999-09-27: If we're in async mode we should
+ _never_ wait for ever -> test on target_is_async_p().
+ However, before we do that we need to ensure that the caller
+ knows how to take the target into/out of async mode. */
+ ret = getpkt_sane (&rs->buf, &rs->buf_size, wait_forever_enabled_p);
+ if (!target_is_async_p ())
+ signal (SIGINT, ofunc);
+ }
+
+ buf = rs->buf;
+
+ remote_stopped_by_watchpoint_p = 0;
+
+ /* We got something. */
+ rs->waiting_for_stop_reply = 0;
+
+ /* Assume that the target has acknowledged Ctrl-C unless we receive
+ an 'F' or 'O' packet. */
+ if (buf[0] != 'F' && buf[0] != 'O')
+ rs->ctrlc_pending_p = 0;
+
+ switch (buf[0])
+ {
+ case 'E': /* Error of some sort. */
+ /* We're out of sync with the target now. Did it continue or
+ not? Not is more likely, so report a stop. */
+ warning (_("Remote failure reply: %s"), buf);
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_0;
+ break;
+ case 'F': /* File-I/O request. */
+ remote_fileio_request (buf, rs->ctrlc_pending_p);
+ rs->ctrlc_pending_p = 0;
+ break;
+ case 'T': case 'S': case 'X': case 'W':
+ {
+ struct stop_reply *stop_reply;
+ struct cleanup *old_chain;
+
+ stop_reply = stop_reply_xmalloc ();
+ old_chain = make_cleanup (do_stop_reply_xfree, stop_reply);
+ remote_parse_stop_reply (buf, stop_reply);
+ discard_cleanups (old_chain);
+ event_ptid = process_stop_reply (stop_reply, status);
+ break;
+ }
+ case 'O': /* Console output. */
+ remote_console_output (buf + 1);
+
+ /* The target didn't really stop; keep waiting. */
+ rs->waiting_for_stop_reply = 1;
+
+ break;
+ case '\0':
+ if (last_sent_signal != TARGET_SIGNAL_0)
+ {
+ /* Zero length reply means that we tried 'S' or 'C' and the
+ remote system doesn't support it. */
+ target_terminal_ours_for_output ();
+ printf_filtered
+ ("Can't send signals to this remote system. %s not sent.\n",
+ target_signal_to_name (last_sent_signal));
+ last_sent_signal = TARGET_SIGNAL_0;
+ target_terminal_inferior ();
+
+ strcpy ((char *) buf, last_sent_step ? "s" : "c");
+ putpkt ((char *) buf);
+
+ /* We just told the target to resume, so a stop reply is in
+ order. */
+ rs->waiting_for_stop_reply = 1;
+ break;
+ }
+ /* else fallthrough */
+ default:
+ warning (_("Invalid remote reply: %s"), buf);
+ /* Keep waiting. */
+ rs->waiting_for_stop_reply = 1;
+ break;
+ }
+
+ if (status->kind == TARGET_WAITKIND_IGNORE)
+ {
+ /* Nothing interesting happened. If we're doing a non-blocking
+ poll, we're done. Otherwise, go back to waiting. */
+ if (options & TARGET_WNOHANG)
+ return minus_one_ptid;
+ else
+ goto again;
+ }
+ else if (status->kind != TARGET_WAITKIND_EXITED
+ && status->kind != TARGET_WAITKIND_SIGNALLED)
+ {
+ if (!ptid_equal (event_ptid, null_ptid))
+ record_currthread (event_ptid);
+ else
+ event_ptid = inferior_ptid;
+ }
+ else
+ /* A process exit. Invalidate our notion of current thread. */
+ record_currthread (minus_one_ptid);
+
+ return event_ptid;
+}
+
+/* Wait until the remote machine stops, then return, storing status in
+ STATUS just as `wait' would. */
+
+static ptid_t
+remote_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status, int options)
+{
+ ptid_t event_ptid;
+
+ if (non_stop)
+ event_ptid = remote_wait_ns (ptid, status, options);
+ else
+ event_ptid = remote_wait_as (ptid, status, options);
+
+ if (target_can_async_p ())
+ {
+ /* If there are are events left in the queue tell the event loop
+ to return here. */
+ if (stop_reply_queue)
+ mark_async_event_handler (remote_async_inferior_event_token);
+ }
+
+ return event_ptid;
+}
+
+/* Fetch a single register using a 'p' packet. */
+
+static int
+fetch_register_using_p (struct regcache *regcache, struct packet_reg *reg)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *buf, *p;
+ char regp[MAX_REGISTER_SIZE];
+ int i;
+
+ if (remote_protocol_packets[PACKET_p].support == PACKET_DISABLE)
+ return 0;
+
+ if (reg->pnum == -1)
+ return 0;
+
+ p = rs->buf;
+ *p++ = 'p';
+ p += hexnumstr (p, reg->pnum);
+ *p++ = '\0';
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ buf = rs->buf;
+
+ switch (packet_ok (buf, &remote_protocol_packets[PACKET_p]))
+ {
+ case PACKET_OK:
+ break;
+ case PACKET_UNKNOWN:
+ return 0;
+ case PACKET_ERROR:
+ error (_("Could not fetch register \"%s\"; remote failure reply '%s'"),
+ gdbarch_register_name (get_regcache_arch (regcache),
+ reg->regnum),
+ buf);
+ }
+
+ /* If this register is unfetchable, tell the regcache. */
+ if (buf[0] == 'x')
+ {
+ regcache_raw_supply (regcache, reg->regnum, NULL);
+ return 1;
+ }
+
+ /* Otherwise, parse and supply the value. */
+ p = buf;
+ i = 0;
+ while (p[0] != 0)
+ {
+ if (p[1] == 0)
+ error (_("fetch_register_using_p: early buf termination"));
+
+ regp[i++] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+ regcache_raw_supply (regcache, reg->regnum, regp);
+ return 1;
+}
+
+/* Fetch the registers included in the target's 'g' packet. */
+
+static int
+send_g_packet (void)
+{
+ struct remote_state *rs = get_remote_state ();
+ int buf_len;
+
+ sprintf (rs->buf, "g");
+ remote_send (&rs->buf, &rs->buf_size);
+
+ /* We can get out of synch in various cases. If the first character
+ in the buffer is not a hex character, assume that has happened
+ and try to fetch another packet to read. */
+ while ((rs->buf[0] < '0' || rs->buf[0] > '9')
+ && (rs->buf[0] < 'A' || rs->buf[0] > 'F')
+ && (rs->buf[0] < 'a' || rs->buf[0] > 'f')
+ && rs->buf[0] != 'x') /* New: unavailable register value. */
+ {
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Bad register packet; fetching a new packet\n");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ }
+
+ buf_len = strlen (rs->buf);
+
+ /* Sanity check the received packet. */
+ if (buf_len % 2 != 0)
+ error (_("Remote 'g' packet reply is of odd length: %s"), rs->buf);
+
+ return buf_len / 2;
+}
+
+static void
+process_g_packet (struct regcache *regcache)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct remote_state *rs = get_remote_state ();
+ struct remote_arch_state *rsa = get_remote_arch_state ();
+ int i, buf_len;