* Backend for gdbfreeplay.
*/
+#include "config.h"
#include <stdio.h>
-#include <stdlib.h>
#include <ctype.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STRING_H
#include <string.h>
+#endif
typedef struct STOPFRAME {
/* frame_id -- a unique identifier per stop frame. */
{
/* Make a pass over the entire file -- cache the record positions. */
char *line, *p;
- int next_id = 0;
unsigned long nextpos;
unsigned long GPC;
if (stopframe[last_cached_frame].pc == 0 ||
stopframe[last_cached_frame].pc == (unsigned long) -1)
stopframe[last_cached_frame].pc = target_pc_from_g (infile);
-
- if (verbose)
- fprintf (stdout, "Found 'g' packet at %u\n",
- stopframe[last_cached_frame].gpos);
}
/* Reset PC after breakpoint? */
stopframe[last_cached_frame].pc = target_pc_from_T (p);
if (verbose)
- fprintf (stdout, "Record event pos at %u\n",
+ fprintf (stdout, "Record event pos at %lu\n",
stopframe [last_cached_frame].eventpos);
}
nextpos = ftell (infile);
gdbwriteline (int fd, char *line)
{
char *end;
- int len, ich;
+ int ich;
char ch;
if (line)
(p = strstr (line, "$S")) != NULL)
{
/* Signal value is two ascii/hex bytes following "$S" or "$T". */
- sig = hex_to_int (p[2]) << 8 + hex_to_int (p[3]);
+ sig = (hex_to_int (p[2]) << 8) + hex_to_int (p[3]);
return sig;
}
return 0;
/* Handle 's' (step) by advancing the cur_frame index. */
if (strstr (request, "$s#73") != NULL)
{
- step_label:
if (cur_frame < last_cached_frame)
cur_frame++;
/* If it's a "$T", give the target a chance to re-compose it
(possibly allowing for DECR_PC_AFTER_BREAK). */
if ((p = strstr (inbuf, "$T")) != NULL)
- return add_checksum (target_compose_T_packet (p));
+ return add_checksum (target_compose_T_packet (p,
+ stopframe[cur_frame].pc,
+ 1 /* breakpoint_p */));
/* If it's a "$S", just return it (FIXME?) */
else
return &inbuf[0];
/* If it's a "$T", give the target a chance to re-compose it
(possibly allowing for DECR_PC_AFTER_BREAK). */
if ((p = strstr (inbuf, "$T")) != NULL)
- return add_checksum (target_compose_T_packet (p));
+ return add_checksum (target_compose_T_packet (p,
+ stopframe[cur_frame].pc,
+ 1 /* breakpoint_p */));
/* If it's a "$S", just return it (FIXME?) */
else
return &inbuf[0];
static char *
fallbacks (FILE *infile, int fd, char *request)
{
+ char *p;
+
/* Handle "Hc0" request. */
if (strstr (request, "$Hc0#db") != NULL)
{
return EMPTY; /* Tell gdb we don't know that one. */
}
+ /* Handle 'G' request (if not handled upstream).
+ Just tell gdb "OK", and otherwise ignore it.
+ The debugger now has its own idea of what the registers are... */
+ if (strstr (request, "$G") != NULL)
+ {
+ if (verbose)
+ fprintf (stdout, "fallbacks: absorbing G request.\n");
+ return OK;
+ }
+
+ /* Handle 'M' or 'X' request (if not handled upstream).
+ There are two ways to go here -- just say "OK", without
+ actually doing anything, or return an error.
+
+ Going to try just saying "OK", for now... */
+ if (strstr (request, "$M") != NULL ||
+ strstr (request, "$X") != NULL)
+ {
+ if (verbose)
+ fprintf (stdout, "fallbacks: absorbing memory write request.\n");
+ return OK;
+ }
+
+ /* Handle 'g' request (if not handled upstream).
+ This is usually at a singlestep event.
+ We need to construct a 'g' packet for gdb from the 'T' packet. */
+ if (strstr (request, "$g#67") != NULL)
+ {
+ /* Find the original event message for this stop event. */
+ fseek (infile, stopframe[cur_frame].eventpos, SEEK_SET);
+ fgets (inbuf, sizeof (inbuf), infile);
+ /* If it's a "$T", give the target a chance to compose a g packet.
+ (possibly allowing for DECR_PC_AFTER_BREAK). */
+ if ((p = strstr (inbuf, "$T")) != NULL)
+ {
+ if (verbose)
+ fprintf (stdout, "fallbacks: constructing 'g' packet.\n");
+ return add_checksum (target_compose_g_packet (p));
+ }
+ /* If it's an 'S' packet, there ain't much we can do
+ (FIXME unles we at least know the PC? */
+ else
+ {
+ if (verbose)
+ fprintf (stdout, "fallbacks: punting on 'g' packet request.\n");
+ return EMPTY;
+ }
+ }
+
/* Default for any other un-handled request -- return empty string. */
if (verbose)
fprintf (stdout, "fallbacks: absorbing unknown request '%s'.\n",
/* Caller has to recompute checksum. */
return reply_buf;
}
+ /* Bail... */
+ return origTpacket;
+}
+
+/*
+ * target_compose_g_packet
+ *
+ * Take the registers from the 'T' packet, and compose them into a
+ * 'g' packet response. Registers for which we have no values will
+ * be filled in with 'xxxx', in the manner of tracepoints.
+ *
+ * Returns: string, g packet reply.
+ */
+
+#define IX86_TARGET_GBYTES 624
+static char gbuffer[IX86_TARGET_GBYTES + 1];
+#define IX86_BOGUS_NUMREGS (IX86_TARGET_GBYTES / 8)
+
+static unsigned long regval[IX86_BOGUS_NUMREGS];
+static int gotreg[IX86_BOGUS_NUMREGS];
+
+char *
+target_compose_g_packet (char *tpac)
+{
+ int i;
+ int regnum;
+ int signum;
+
+ /* See which regs we can get from the T packet. Assume none... */
+ for (i = 0; i < IX86_BOGUS_NUMREGS; i++)
+ gotreg[i] = 0;
+
+ /* OK, scan off the prefix -- $T plus signal number. */
+ if (*tpac++ == '$' && *tpac++ == 'T')
+ {
+ /* We won't actually use signum. */
+ signum = (hex_to_int (*tpac++) << 4) + hex_to_int (*tpac++);
+ while (*tpac)
+ {
+ regnum = (hex_to_int (*tpac++) << 4) + hex_to_int (*tpac++);
+ if (*tpac++ == ':')
+ {
+ gotreg[regnum] = 1;
+ regval[regnum] = ix86_hex_to_unsigned_long (expand_rle (tpac));
+ tpac = strchr (tpac, ';');
+ }
+ else goto gpacket_fail;
+
+ if (tpac && *tpac == ';')
+ tpac++;
+ else goto gpacket_fail;
+
+ if (strncmp (tpac, "thread", 6) == 0)
+ break;
+ }
+
+ /* Got values, now get to composin'. */
+ strcpy (gbuffer, "$");
+ for (i = 0; i < IX86_BOGUS_NUMREGS; i++)
+ if (gotreg[i])
+ strcat (gbuffer, ix86_unsigned_long_to_hex (regval[i]));
+ else
+ strcat (gbuffer, "xxxxxxxx");
+
+ /* Return composed g packet reply.
+ Caller has responsibility of appending checksum. */
+ return gbuffer;
+ }
+ gpacket_fail:
+ /* Fail. */
+ return NULL;
}