• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

GNU Binutils with patches for OS216


Commit MetaInfo

Revisionf5fa7161cadee2056fa62142dfbbc3b5dbdab67e (tree)
Time2008-06-22 04:41:01
AuthorMichael Snyder <msnyder@vmwa...>
CommiterMichael Snyder

Log Message

2008-06-21 Michael Snyder <msnyder@specifix.com>

* gdbfreeplay-front.c: New file. Extended gdbreplay.
* gdbfreeplay-back.c: New file.
* gdbfreeplay-i386.c: New file.
* gdbfreeplay.h: New file.
* remote-breakpoint.c: New file.
* remote-breakpoint.h: New file.
* Makefile.in: Add rules for gdb-freeplay.
* configure.srv: Ditto.
* configure.ac: Ditto.
* configure: Regenerate.

Change Summary

Incremental Difference

--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,16 @@
1+2008-06-21 Michael Snyder <msnyder@specifix.com>
2+
3+ * gdbfreeplay-front.c: New file. Extended gdbreplay.
4+ * gdbfreeplay-back.c: New file.
5+ * gdbfreeplay-i386.c: New file.
6+ * gdbfreeplay.h: New file.
7+ * remote-breakpoint.c: New file.
8+ * remote-breakpoint.h: New file.
9+ * Makefile.in: Add rules for gdb-freeplay.
10+ * configure.srv: Ditto.
11+ * configure.ac: Ditto.
12+ * configure: Regenerate.
13+
114 2008-06-06 Daniel Jacobowitz <dan@codesourcery.com>
215
316 * Makefile.in (gdbreplay.o): New rule.
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -136,6 +136,8 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c \
136136
137137 DEPFILES = @GDBSERVER_DEPFILES@
138138
139+FREEPLAY_DEPFILES = @GDBFREEPLAY_DEPFILES@
140+
139141 LIBOBJS = @LIBOBJS@
140142
141143 SOURCES = $(SFILES)
@@ -199,6 +201,13 @@ gdbreplay$(EXEEXT): gdbreplay.o version.o
199201 ${CC-LD} $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) -o gdbreplay$(EXEEXT) $^ \
200202 $(XM_CLIBS)
201203
204+gdb-freeplay$(EXEEXT): gdbfreeplay-front.o gdbfreeplay-back.o version.o \
205+ $(FREEPLAY_DEPFILES) remote-breakpoint.o
206+ rm -f gdb-freeplay$(EXEEXT)
207+ ${CC-LD} $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) -o gdb-freeplay$(EXEEXT) $^ \
208+ $(XM_CLIBS)
209+
210+
202211 # Put the proper machine-specific files first, so M-. on a machine
203212 # specific routine gets the one for the correct machine.
204213 # The xyzzy stuff below deals with empty DEPFILES
@@ -217,7 +226,8 @@ tags: TAGS
217226 clean:
218227 rm -f *.o ${ADD_FILES} *~
219228 rm -f version.c
220- rm -f gdbserver$(EXEEXT) gdbreplay$(EXEEXT) core make.log
229+ rm -f gdbserver$(EXEEXT) gdbreplay$(EXEEXT) gdb-freeplay$(EXEEXT)
230+ rm -f core make.log
221231 rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m32r.c reg-m68k.c
222232 rm -f reg-sh.c reg-spu.c reg-x86-64.c reg-i386-linux.c
223233 rm -f reg-cris.c reg-crisv32.c reg-x86-64-linux.c reg-xtensa.c
@@ -289,6 +299,8 @@ target.o: target.c $(server_h)
289299 thread-db.o: thread-db.c $(server_h) $(gdb_proc_service_h)
290300 utils.o: utils.c $(server_h)
291301 gdbreplay.o: gdbreplay.c config.h
302+gdbfreeplay-front.o: gdbfreeplay-front.c gdbfreeplay.h
303+gdbfreeplay-back.o: gdbfreeplay-back.c gdbfreeplay.h
292304
293305 signals.o: ../signals/signals.c $(server_h)
294306 $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -310,7 +310,7 @@ ac_includes_default="\
310310 # include <unistd.h>
311311 #endif"
312312
313-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP LIBOBJS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI RDYNAMIC GDBSERVER_DEPFILES GDBSERVER_LIBS USE_THREAD_DB srv_xmlbuiltin srv_xmlfiles LTLIBOBJS'
313+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP LIBOBJS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI RDYNAMIC GDBSERVER_DEPFILES GDBSERVER_LIBS USE_THREAD_DB srv_xmlbuiltin srv_xmlfiles GDBFREEPLAY_DEPFILES LTLIBOBJS'
314314 ac_subst_files=''
315315
316316 # Initialize some variables set by options.
@@ -4491,6 +4491,8 @@ fi
44914491
44924492 GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_hostio_err_objs $srv_thread_depfiles"
44934493 GDBSERVER_LIBS="$srv_libs"
4494+GDBFREEPLAY_DEPFILES="$freeplay_tgtobj"
4495+
44944496
44954497
44964498
@@ -5150,6 +5152,7 @@ s,@GDBSERVER_LIBS@,$GDBSERVER_LIBS,;t t
51505152 s,@USE_THREAD_DB@,$USE_THREAD_DB,;t t
51515153 s,@srv_xmlbuiltin@,$srv_xmlbuiltin,;t t
51525154 s,@srv_xmlfiles@,$srv_xmlfiles,;t t
5155+s,@GDBFREEPLAY_DEPFILES@,$GDBFREEPLAY_DEPFILES,;t t
51535156 s,@LTLIBOBJS@,$LTLIBOBJS,;t t
51545157 CEOF
51555158
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -183,12 +183,14 @@ fi
183183
184184 GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_hostio_err_objs $srv_thread_depfiles"
185185 GDBSERVER_LIBS="$srv_libs"
186+GDBFREEPLAY_DEPFILES="$freeplay_tgtobj"
186187
187188 AC_SUBST(GDBSERVER_DEPFILES)
188189 AC_SUBST(GDBSERVER_LIBS)
189190 AC_SUBST(USE_THREAD_DB)
190191 AC_SUBST(srv_xmlbuiltin)
191192 AC_SUBST(srv_xmlfiles)
193+AC_SUBST(GDBFREEPLAY_DEPFILES)
192194
193195 AC_OUTPUT(Makefile,
194196 [case x$CONFIG_HEADERS in
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -10,6 +10,7 @@
1010 # target method.
1111 # srv_xmlfiles All XML files which should be available for
1212 # gdbserver in this configuration.
13+# freeplay_tgtobj Target module for gdb-freeplay.
1314 #
1415 # In addition, on GNU/Linux the following shell variables will be set:
1516 # srv_linux_regsets Set to "yes" if ptrace(PTRACE_GETREGS) and friends
@@ -54,16 +55,19 @@ case "${target}" in
5455 ;;
5556 i[34567]86-*-cygwin*) srv_regobj=reg-i386.o
5657 srv_tgtobj="win32-low.o win32-i386-low.o"
58+ freeplay_tgtobj="gdbfreeplay-i386.o"
5759 ;;
5860 i[34567]86-*-linux*) srv_regobj=reg-i386-linux.o
5961 srv_tgtobj="linux-low.o linux-i386-low.o i387-fp.o"
6062 srv_linux_usrregs=yes
6163 srv_linux_regsets=yes
6264 srv_linux_thread_db=yes
65+ freeplay_tgtobj="gdbfreeplay-i386.o"
6366 ;;
6467 i[34567]86-*-mingw*) srv_regobj=reg-i386.o
6568 srv_tgtobj="win32-low.o win32-i386-low.o"
6669 srv_mingw=yes
70+ freeplay_tgtobj="gdbfreeplay-i386.o"
6771 ;;
6872 ia64-*-linux*) srv_regobj=reg-ia64.o
6973 srv_tgtobj="linux-low.o linux-ia64-low.o"
--- /dev/null
+++ b/gdb/gdbserver/gdbfreeplay-back.c
@@ -0,0 +1,934 @@
1+/*
2+ * gdbfreeplay-back.c
3+ *
4+ * Backend for gdbfreeplay.
5+ */
6+
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <ctype.h>
10+#include <string.h>
11+
12+typedef struct STOPFRAME {
13+ /* frame_id -- a unique identifier per stop frame. */
14+ unsigned int frame_id;
15+ /* pc -- address of the next instruction to be "executed". */
16+ unsigned long pc;
17+ /* predecr_pc -- address that will be reported by a breakpoint.
18+ These two are different on some targets, see gdb source code,
19+ DECR_PC_AFTER_BREAK. */
20+ unsigned long predecr_pc;
21+ unsigned long eventpos;
22+ unsigned long gpos;
23+} StopFrame;
24+
25+StopFrame *stopframe;
26+int last_cached_frame = 0;
27+int framecache_size = 0;
28+int cur_frame = -1;
29+
30+#include "gdbfreeplay.h"
31+
32+/*
33+ * scan_gdbreplay_file
34+ *
35+ * Make a pass through the replay log, noting the positions
36+ * of the stop events and certain packets within them.
37+ *
38+ * Returns: FAIL, PASS.
39+ */
40+
41+#define INBUF_SIZE 4096
42+static char inbuf[INBUF_SIZE];
43+
44+#define GDB_LINEBUF_SIZE 4096
45+static char gdb_linebuf[GDB_LINEBUF_SIZE];
46+
47+static enum successcode
48+scan_gdbreplay_file (FILE *infile)
49+{
50+ /* Make a pass over the entire file -- cache the record positions. */
51+ char *line, *p;
52+ int next_id = 0;
53+ unsigned long nextpos;
54+ unsigned long GPC;
55+
56+ /* First skip empty lines. */
57+ do {
58+ nextpos = ftell (infile);
59+ line = fgets (inbuf, sizeof (inbuf), infile);
60+ } while (line != NULL && inbuf[0] == '\n');
61+
62+ if (line == NULL)
63+ return FAIL; /* End of file, nothing there. */
64+
65+ /* Now for the main loop.
66+ *
67+ * Scan the rest of the file, recording stop events etc.
68+ */
69+ do {
70+ /* 'g' packet message? */
71+ if (strstr (line, "$g#67") != NULL)
72+ {
73+ /* Record position of 'g' packet (next line). */
74+ stopframe[last_cached_frame].gpos = ftell (infile);
75+
76+ /* See if we need to grab the PC from this packet. */
77+ if (stopframe[last_cached_frame].pc == 0 ||
78+ stopframe[last_cached_frame].pc == (unsigned long) -1)
79+ stopframe[last_cached_frame].pc = target_pc_from_g (infile);
80+
81+ if (verbose)
82+ fprintf (stdout, "Found 'g' packet at %u\n",
83+ stopframe[last_cached_frame].gpos);
84+ }
85+
86+ /* Reset PC after breakpoint? */
87+ else if ((p = strstr (line, "$G")) != NULL)
88+ {
89+ GPC = target_pc_from_G (p);
90+ if (stopframe[last_cached_frame].pc == 0 ||
91+ stopframe[last_cached_frame].pc == (unsigned long) -1)
92+ {
93+ /* Unlikely, but if we need to, we can just grab this PC. */
94+ stopframe[last_cached_frame].pc = GPC;
95+ }
96+ else if (stopframe[last_cached_frame].pc == GPC + 1)
97+ {
98+ /* OK, this is gdb decrementing the PC after a breakpoint. */
99+ stopframe[last_cached_frame].predecr_pc =
100+ stopframe[last_cached_frame].pc;
101+ stopframe[last_cached_frame].pc = GPC;
102+ }
103+ }
104+
105+ /* Stop event message? */
106+ else if ((p = strstr (line, "$T")) != NULL ||
107+ (p = strstr (line, "$S")) != NULL)
108+ {
109+ if (last_cached_frame >= framecache_size - 1)
110+ {
111+ /* Time to grow the frame cache buffer. */
112+ framecache_size += 2048;
113+ if (verbose)
114+ fprintf (stdout, "Growing frame cache to %d\n",
115+ framecache_size);
116+ stopframe = realloc (stopframe,
117+ framecache_size * sizeof (stopframe[0]));
118+ }
119+ /* Special case: 0th frame.
120+
121+ On the first pass, the FIRST time I see a stop event
122+ for the 0th frame, I will not increment the stopframe
123+ index.
124+
125+ The 0th frame is special, in that its "stop event"
126+ happens not as a result of a real stop event, but
127+ as a result of gdb sending the "?" query. Therefore
128+ the apparent event falls in the middle of the frame.
129+ */
130+
131+ if (last_cached_frame != 0 ||
132+ stopframe [last_cached_frame].eventpos != 0)
133+ last_cached_frame++;
134+
135+ /* Since we now have a known frame, default to using it. */
136+ cur_frame = 0;
137+ stopframe[last_cached_frame].eventpos = nextpos + p - line;
138+
139+ if (p[1] == 'T')
140+ stopframe[last_cached_frame].pc = target_pc_from_T (p);
141+
142+ if (verbose)
143+ fprintf (stdout, "Record event pos at %u\n",
144+ stopframe [last_cached_frame].eventpos);
145+ }
146+ nextpos = ftell (infile);
147+ line = fgets (inbuf, sizeof (inbuf), infile);
148+ } while (line != NULL);
149+
150+ return PASS;
151+}
152+
153+/*
154+ * gdbfreeplay_open
155+ *
156+ * Open the gdbfreeplay "target", which mainly means opening
157+ * the gdbreplay log file.
158+ *
159+ * Returns: FAIL, PASS.
160+ */
161+
162+static FILE *replay_file;
163+
164+enum successcode
165+gdbfreeplay_open (char *filename)
166+{
167+ if ((replay_file = fopen (filename, "r")) == NULL)
168+ {
169+ fprintf (stderr, "GDBFREEPLAY: could not open file %s for input.\n",
170+ filename);
171+ return FAIL;
172+ }
173+
174+ return scan_gdbreplay_file (replay_file);
175+}
176+
177+/*
178+ * gdbreadline
179+ *
180+ * Read a line of input from gdb (from the socket).
181+ */
182+
183+static char *
184+gdbreadline (int fd)
185+{
186+ char *p = gdb_linebuf;
187+ int saw_dollar = 0;
188+ int saw_pound = 0;
189+ int cksum_chars = 0;
190+
191+ while (p < gdb_linebuf + sizeof (gdb_linebuf) - 1)
192+ {
193+ read (fd, p, 1);
194+ p[1] = '\0';
195+ switch (p[0]) {
196+ case '+':
197+ /* Receive "ack" from gdb.
198+ Assuming it is first char in buffer, ignore. */
199+ if (p - gdb_linebuf != 0)
200+ fprintf (stdout, "gdbreadline: '+' ack in middle of line?\n");
201+ continue;
202+ break;
203+ case '-':
204+ if (p - gdb_linebuf == 0)
205+ {
206+ /* Receive "nack" from gdb. FIXME what to do? */
207+ return gdb_linebuf;
208+ }
209+ goto default_label;
210+ break;
211+ case '$':
212+ if (saw_dollar)
213+ fprintf (stdout, "gdbreadline: two '$' in one line:\n\t'%s'\n",
214+ gdb_linebuf);
215+
216+ saw_dollar = 1;
217+ break;
218+ case '#':
219+ if (!saw_dollar)
220+ fprintf (stdout, "gdbreadline: '#' before '$':\n\t'%s'\n",
221+ gdb_linebuf);
222+
223+ if (saw_pound)
224+ fprintf (stdout, "gdbreadline: two '#' in one line:\n\t'%s'\n",
225+ gdb_linebuf);
226+
227+ saw_pound = 1;
228+ break;
229+ default:
230+ default_label:
231+ if (saw_pound)
232+ cksum_chars++;
233+ if (cksum_chars >= 2)
234+ {
235+ /* Got a complete message. */
236+ return gdb_linebuf;
237+ }
238+ break;
239+ }
240+ ++p;
241+ }
242+ /* Shouldn't get here except for buffer overflow. */
243+ fprintf (stdout, "gdbreadline: buffer overflow?\n");
244+ return gdb_linebuf;
245+}
246+
247+/*
248+ * find_reply
249+ *
250+ * Given a filepos pointing to just after a given gdb request,
251+ * find and return a char * containing the reply to that request.
252+ *
253+ * Return NULL on failure.
254+ */
255+
256+static char *
257+find_reply (FILE *logfile, long filepos)
258+{
259+ char *line;
260+
261+ if (filepos == -1)
262+ return NULL;
263+
264+ /* Position the file (it's probably already there...) */
265+ fseek (logfile, filepos, SEEK_SET);
266+ /* In principle, the next input line should contain the reply. */
267+ line = fgets (inbuf, sizeof (inbuf), logfile);
268+
269+ return line;
270+}
271+
272+/*
273+ * frame_find_request
274+ *
275+ * Given a request from gdb, in the form of a string,
276+ * find an identical request within the current frame
277+ * of the gdbreplay log file.
278+ *
279+ * Return a file position immediately following the request.
280+ */
281+
282+static long
283+frame_find_request (FILE *logfile, char *request)
284+{
285+ long curpos;
286+ char *line;
287+
288+ if (cur_frame >= 0)
289+ {
290+ /* Position the input at the beginning of the frame.
291+ SPECIAL CASE: for frame zero, go to the beginning of the log.
292+ This is so we can find gdb requests that preceed the first
293+ stop-event message.
294+ */
295+ if (cur_frame == 0)
296+ curpos = 0;
297+ else
298+ curpos = stopframe[cur_frame].eventpos;
299+ fseek (logfile, curpos, SEEK_SET);
300+ /* Now search for a matching request. */
301+ while (curpos < stopframe[cur_frame + 1].eventpos)
302+ {
303+ line = fgets (inbuf, sizeof (inbuf), logfile);
304+ /* End of input? */
305+ if (line == NULL)
306+ break;
307+ curpos = ftell (logfile);
308+ if (strstr (line, request) != NULL)
309+ {
310+ /* Matching request found. Return position. */
311+ return curpos;
312+ }
313+ }
314+ }
315+
316+ /* Not found. */
317+ return -1;
318+}
319+
320+/*
321+ * gdb_ack
322+ *
323+ * Send an ack to gdb.
324+ * Returns void.
325+ */
326+
327+static void
328+gdb_ack (int fd)
329+{
330+ static const char *ack = "+";
331+ write (fd, ack, 1);
332+}
333+
334+/*
335+ * hex_to_int
336+ */
337+
338+int
339+hex_to_int (int c)
340+{
341+ if (c >= '0' && c <= '9')
342+ return c - '0';
343+ else if (c >= 'a' && c <= 'f')
344+ return c - 'a' + 10;
345+ else if (c >= 'A' && c <= 'F')
346+ return c - 'F' + 10;
347+ else
348+ return 0;
349+}
350+
351+/*
352+ * int_to_hex
353+ *
354+ * (lifted from gdb)
355+ */
356+
357+int
358+int_to_hex (int nib)
359+{
360+ if (nib < 10)
361+ return '0' + nib;
362+ else
363+ return 'a' + nib - 10;
364+}
365+
366+#if 0
367+/*
368+ * tohex
369+ *
370+ * Borrowed from gdbreplay.
371+ */
372+
373+static int
374+tohex (int ch)
375+{
376+ if (ch >= '0' && ch <= '9')
377+ {
378+ return (ch - '0');
379+ }
380+ if (ch >= 'A' && ch <= 'F')
381+ {
382+ return (ch - 'A' + 10);
383+ }
384+ if (ch >= 'a' && ch <= 'f')
385+ {
386+ return (ch - 'a' + 10);
387+ }
388+ fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
389+ fflush (stderr);
390+ exit (1);
391+}
392+#endif
393+
394+#define EOI 0xdeadbeef
395+
396+/*
397+ * convert_logchar
398+ *
399+ * Adapted from gdbreplay.
400+ * Some characters in the log are escaped, and
401+ * need to be translated before being sent back
402+ * to gdb.
403+ *
404+ * Returns a de-escaped char.
405+ */
406+
407+static int
408+convert_logchar (char **logp)
409+{
410+ int ch, ch2;
411+
412+ ch = *(*logp)++;
413+ switch (ch)
414+ {
415+ case '\0':
416+ case '\n':
417+ ch = EOI; /* End of input (out of band). */
418+ break;
419+ case '\\':
420+ ch = *(*logp)++;
421+ switch (ch)
422+ {
423+ case '\\':
424+ break;
425+ case 'b':
426+ ch = '\b';
427+ break;
428+ case 'f':
429+ ch = '\f';
430+ break;
431+ case 'n':
432+ ch = '\n';
433+ break;
434+ case 'r':
435+ ch = '\r';
436+ break;
437+ case 't':
438+ ch = '\t';
439+ break;
440+ case 'v':
441+ ch = '\v';
442+ break;
443+ case 'x':
444+ ch2 = *(*logp)++;
445+ ch = hex_to_int (ch2) << 4;
446+ ch2 = *(*logp)++;
447+ ch |= hex_to_int (ch2);
448+ break;
449+ default:
450+ /* Treat any other char as just itself */
451+ break;
452+ }
453+ default:
454+ break;
455+ }
456+ return (ch);
457+}
458+
459+/*
460+ * gdbwriteline
461+ *
462+ * Send a line of data to gdb, stripped of any
463+ * prefix or suffix stuff.
464+ *
465+ * Prefix is anything preceeding a '$'.
466+ * Suffix is anything following a "#xx" (including any newlines).
467+ *
468+ * Returns void.
469+ */
470+
471+static void
472+gdbwriteline (int fd, char *line)
473+{
474+ char *end;
475+ int len, ich;
476+ char ch;
477+
478+ if (line)
479+ {
480+ /* Strip prefix. */
481+ while (*line && *line != '$')
482+ line++;
483+ if (*line)
484+ {
485+ /* Strip suffix. */
486+ end = strchr (line, '#');
487+ if (end && *end)
488+ {
489+ /* Got line, send it. */
490+ end[3] = '\0';
491+ while ((ich = convert_logchar (&line)) != EOI)
492+ {
493+ ch = ich;
494+ write (fd, &ch, 1);
495+ }
496+ }
497+ }
498+ }
499+}
500+
501+/*
502+ * stopframe_signal
503+ *
504+ * Return the signal number for which the stopframe stopped.
505+ * This is a brute force implementation. Probably should plan
506+ * on caching the value to speed things up.
507+ */
508+
509+static int
510+stopframe_signal (FILE *infile, int id)
511+{
512+ char *line, *p;
513+ int sig;
514+
515+ fseek (infile, stopframe[id].eventpos, SEEK_SET);
516+ line = fgets (inbuf, sizeof (inbuf), infile);
517+
518+ if ((p = strstr (line, "$T")) != NULL ||
519+ (p = strstr (line, "$S")) != NULL)
520+ {
521+ /* Signal value is two ascii/hex bytes following "$S" or "$T". */
522+ sig = hex_to_int (p[2]) << 8 + hex_to_int (p[3]);
523+ return sig;
524+ }
525+ return 0;
526+}
527+
528+/*
529+ * freeplay_find_event
530+ *
531+ * Scan (forward or backward) thru the stop events,
532+ * looking for a reason to stop now (assuming gdb has
533+ * asked us to continue).
534+ *
535+ * Returns event frame index, or -1 for failure.
536+ */
537+
538+static int
539+freeplay_find_event (FILE *infile, int start, enum direction_code direction)
540+{
541+ int i;
542+ int signum;
543+
544+ /* Here's a strange loop for you: goes forward or backward. */
545+ for (i = start;
546+ i >= 0 && i < last_cached_frame;
547+ direction == DIR_FORWARD ? i++ : i--)
548+ {
549+ signum = stopframe_signal (infile, i);
550+ /* FIXME we need some modal handling for SIGTRAP. */
551+ if (signum != 0 && signum != 5)
552+ {
553+ /* Here's an event we can stop at, regardless of breakpoints. */
554+ /* FIXME: there is some signal-ignoring stuff to be looked at. */
555+ return i;
556+ }
557+ else if (remote_breakpoint_here_p (SOFTWARE_BP, stopframe[i].pc) == PASS)
558+ {
559+ /* Found a breakpoint.
560+ FIXME need some DECR_PC_AFTER_BREAK handling. */
561+ return i;
562+ }
563+ }
564+ /* Found no reason to stop. */
565+ return -1;
566+}
567+
568+/*
569+ * add_checksum
570+ *
571+ * Compute the checksum for a string that will go to gdb,
572+ * and concatenate it onto the string.
573+ *
574+ * Returns input string modified in place (better have room!)
575+ */
576+
577+char *
578+add_checksum (char *inbuf)
579+{
580+ int cksum = 0;
581+ char *p = inbuf;
582+
583+ /* If the string doesn't start with a '$', it's broken. */
584+ if (*p++ != '$')
585+ return inbuf;
586+
587+ /* Now add up the cksum. */
588+ while (*p)
589+ {
590+ /* If there's already a '#', it doesn't count toward the cksum.
591+ Stop there. */
592+ if (*p == '#')
593+ break;
594+ cksum += *p++;
595+ }
596+
597+ /* Add a '#' at the end, even if it's already there, and
598+ overwrite any old checksum that may be there already. */
599+ *p++ = '#';
600+ *p++ = int_to_hex ((cksum >> 4) & 0xf);
601+ *p++ = int_to_hex (cksum & 0xf);
602+ *p++ = '\0';
603+
604+ /* Done. */
605+ return inbuf;
606+}
607+
608+/*
609+ * handle_special_case
610+ *
611+ * Handle these requests locally, rather than through the replay buffer.
612+ *
613+ * Returns: a string reply for gdb.
614+ */
615+
616+static char OK[8] = "$OK#9a";
617+static char EMPTY[8] = "$#00";
618+static char STOP[8] = "$S00#44";
619+static char E01[8] = "$E01#a6";
620+
621+static char *
622+handle_special_case (FILE *infile, int fd, char *request)
623+{
624+ unsigned long addr;
625+ unsigned long len;
626+ int next_event_frame;
627+ char *p;
628+
629+ /* Handle 'k' (kill) request by exiting. */
630+ if (strstr (request, "$k#6b") != NULL)
631+ {
632+ /* Well, to PROPERLY honor the 'kill' request,
633+ we need to actually shoot ourselves in the head... */
634+ gdb_ack (fd);
635+ fprintf (stdout, "gdbfreeplay -- killed by gdb.\n");
636+ exit (0);
637+ }
638+
639+ /* Handle 'D' (detach) request by exiting.
640+ FIXME might want to stay alive and offer the socket again. */
641+ if (strstr (request, "$D#44") != NULL)
642+ {
643+ /* OK, we're not yet set up to close and re-open the socket,
644+ and a new gdb does not seem able to re-attach, so for now
645+ let's actually quit. */
646+ gdb_ack (fd);
647+ gdbwriteline (fd, OK);
648+ fprintf (stdout, "gdbfreeplay -- gdb has detached. Exiting.\n");
649+ exit (0);
650+ }
651+
652+ /* Handle "monitor verbose on". */
653+ if (strstr (request, "$qRcmd,766572626f7365206f6e#d6") != NULL)
654+ {
655+ verbose = 1;
656+ return OK;
657+ }
658+
659+ /* Handle "monitor verbose off". */
660+ if (strstr (request, "$qRcmd,766572626f7365206f6666#13") != NULL)
661+ {
662+ verbose = 0;
663+ return OK;
664+ }
665+
666+ /* Handle 's' (step) by advancing the cur_frame index. */
667+ if (strstr (request, "$s#73") != NULL)
668+ {
669+ step_label:
670+ if (cur_frame < last_cached_frame)
671+ cur_frame++;
672+
673+ if (stopframe[cur_frame].eventpos != 0)
674+ {
675+ return find_reply (infile,
676+ stopframe[cur_frame].eventpos);
677+ }
678+ else
679+ {
680+ /* Not sure how this could even happen, but... */
681+ return STOP;
682+ }
683+ }
684+
685+ /* Handle 'bs' (reverse stepi) by decrementing the cur_frame index. */
686+ if (strstr (request, "$bs#d5") != NULL)
687+ {
688+ if (cur_frame > 0)
689+ cur_frame--;
690+
691+ if (stopframe[cur_frame].eventpos != 0)
692+ {
693+ return find_reply (infile,
694+ stopframe[cur_frame].eventpos);
695+ }
696+ else
697+ {
698+ /* Not sure how this could even happen, but... */
699+ return STOP;
700+ }
701+ }
702+
703+ /* Handle 'c' (continue) by searching the cache for a stop event. */
704+ if (strstr (request, "$c#63") != NULL)
705+ {
706+ next_event_frame = freeplay_find_event (infile, cur_frame, DIR_FORWARD);
707+ if (next_event_frame != -1)
708+ {
709+ /* Got a stop event. Make it the current frame, and tell gdb.
710+ */
711+ cur_frame = next_event_frame;
712+#if 0
713+ /* FIXME: we want to do something about DECR_PC_AFTER_BREAK. */
714+ return find_reply (infile,
715+ stopframe[cur_frame].eventpos);
716+#endif
717+ }
718+ else
719+ {
720+ /* FIXME now what? Go to final frame? */
721+ cur_frame = last_cached_frame - 1;
722+#if 0
723+ /* FIXME: we want to do something about DECR_PC_AFTER_BREAK. */
724+ return find_reply (infile,
725+ stopframe[cur_frame].eventpos);
726+#endif
727+ }
728+#if 1
729+ /* Find the original event message for this stop event. */
730+ fseek (infile, stopframe[cur_frame].eventpos, SEEK_SET);
731+ fgets (inbuf, sizeof (inbuf), infile);
732+ /* If it's a "$T", give the target a chance to re-compose it
733+ (possibly allowing for DECR_PC_AFTER_BREAK). */
734+ if ((p = strstr (inbuf, "$T")) != NULL)
735+ return add_checksum (target_compose_T_packet (p));
736+ /* If it's a "$S", just return it (FIXME?) */
737+ else
738+ return &inbuf[0];
739+#endif
740+ }
741+
742+ /* Handle 'bc' (revese continue) by searching the cache for a stop event. */
743+ if (strstr (request, "$bc#c5") != NULL)
744+ {
745+ next_event_frame = freeplay_find_event (infile, cur_frame, DIR_BACKWARD);
746+ if (next_event_frame != -1)
747+ {
748+ /* Got a stop event. Make it the current frame, and tell gdb.
749+ */
750+ cur_frame = next_event_frame;
751+#if 0
752+ /* FIXME: we want to do something about DECR_PC_AFTER_BREAK. */
753+ return find_reply (infile,
754+ stopframe[cur_frame].eventpos);
755+#endif
756+ }
757+ else
758+ {
759+ /* FIXME now what? Go to initial frame? */
760+ cur_frame = 0;
761+#if 0
762+ /* FIXME: we want to do something about DECR_PC_AFTER_BREAK. */
763+ return find_reply (infile,
764+ stopframe[cur_frame].eventpos);
765+#endif
766+ }
767+#if 1
768+ /* Find the original event message for this stop event. */
769+ fseek (infile, stopframe[cur_frame].eventpos, SEEK_SET);
770+ fgets (inbuf, sizeof (inbuf), infile);
771+ /* If it's a "$T", give the target a chance to re-compose it
772+ (possibly allowing for DECR_PC_AFTER_BREAK). */
773+ if ((p = strstr (inbuf, "$T")) != NULL)
774+ return add_checksum (target_compose_T_packet (p));
775+ /* If it's a "$S", just return it (FIXME?) */
776+ else
777+ return &inbuf[0];
778+#endif
779+ }
780+
781+ /* Handle Z0 set breakpoint. */
782+ if ((p = strstr (request, "$Z0")) != NULL)
783+ {
784+ if (p[3] == ',')
785+ {
786+ addr = strtoul (p + 4, &p, 16);
787+ if (p[0] == ',')
788+ {
789+ len = strtoul (p + 1, NULL, 16);
790+ remote_set_breakpoint (SOFTWARE_BP, addr, len);
791+ return OK;
792+ }
793+ }
794+ }
795+
796+ /* Handle z0 remove breakpoint. */
797+ if ((p = strstr (request, "$z0")) != NULL)
798+ {
799+ if (p[3] == ',')
800+ {
801+ addr = strtoul (p + 4, &p, 16);
802+ if (p[0] == ',')
803+ {
804+ len = strtoul (p + 1, NULL, 16);
805+ remote_remove_breakpoint (SOFTWARE_BP, addr, len);
806+ return OK;
807+ }
808+ }
809+ }
810+
811+ /* Handle "vCont" by saying we can't do it.
812+ FIXME we could do it, and moreover 'fallbacks' could handle this. */
813+ if (strstr (request, "$vCont") != 0)
814+ return EMPTY;
815+
816+ /* TODO: vCont, M, X, G, P/p, tfind... */
817+
818+ /* Let the replay buffer handle it. */
819+ return NULL;
820+}
821+
822+/*
823+ * fallbacks
824+ *
825+ * Attempt to handle requests that were not handled otherwise.
826+ * Returns: char * or NULL.
827+ */
828+
829+static char *
830+fallbacks (FILE *infile, int fd, char *request)
831+{
832+ /* Handle "Hc0" request. */
833+ if (strstr (request, "$Hc0#db") != NULL)
834+ {
835+ /* Debugger just wants to set the "continue thread" to zero.
836+ Don't know why this isn't in the replay cache, but it's
837+ harmless, just say OK. */
838+ if (verbose)
839+ fprintf (stdout, "fallbacks: absorbing 'Hc0'\n");
840+ return OK;
841+ }
842+ /* Handle un-cached memory request (if not handled upstream). */
843+ if (strstr (request, "$m") != NULL)
844+ {
845+ /* FIXME this need not happen so often,
846+ once we do a better job of simulating memory. */
847+ if (verbose)
848+ fprintf (stdout, "fallbacks: failing memory request '%s'.\n",
849+ request);
850+ return E01;
851+ }
852+ /* Handle P/p requests (if they weren't handled upstream). */
853+ if (strstr (request, "$p") != NULL ||
854+ strstr (request, "$p") != NULL)
855+ {
856+ if (verbose)
857+ fprintf (stdout, "fallbacks: absorbing P/p request.\n");
858+ return EMPTY; /* Tell gdb we don't know that one. */
859+ }
860+
861+ /* Default for any other un-handled request -- return empty string. */
862+ if (verbose)
863+ fprintf (stdout, "fallbacks: absorbing unknown request '%s'.\n",
864+ request);
865+ return EMPTY;
866+}
867+
868+/*
869+ * gdbfreeplay
870+ *
871+ * This is the function that manages the interaction with gdb.
872+ */
873+
874+void
875+gdbfreeplay (int fd)
876+{
877+ char *request;
878+ char *reply;
879+
880+ /* Process requests from gdb. */
881+ while (1)
882+ {
883+ /* Read next request from gdb. */
884+ request = gdbreadline (fd);
885+ if (verbose)
886+ fprintf (stdout, "gdb request: %s\n", request);
887+
888+ /* FIXME -- this is where we should handle special cases, including:
889+ -- kill $k#6b
890+ -- detach $D#44
891+ -- step $s#73
892+ -- backstep
893+ -- continue $c#63
894+ -- back-cont
895+ -- breakpoint $Z0...
896+ -- vCont
897+ -- M
898+ -- X
899+ -- G
900+ -- P/p
901+ -- tfind
902+ */
903+
904+ reply = handle_special_case (replay_file, fd, request);
905+
906+ if (reply == NULL)
907+ {
908+ /* Now see if we have a matching request in the current frame. */
909+ reply = find_reply (replay_file,
910+ frame_find_request (replay_file, request));
911+ }
912+
913+ if (reply == NULL)
914+ {
915+ /* Found no matching request in the current frame.
916+ Do fall-backs and last resorts. */
917+ reply = fallbacks (replay_file, fd, request);
918+ }
919+
920+ if (verbose)
921+ fprintf (stdout, "freeplay reply: %s\n",
922+ reply == NULL ? "<not found>" : reply);
923+
924+ if (reply)
925+ {
926+ gdb_ack (fd);
927+ gdbwriteline (fd, reply);
928+ }
929+ else
930+ {
931+ /* FIXME -- gotta say something back... */
932+ }
933+ }
934+}
--- /dev/null
+++ b/gdb/gdbserver/gdbfreeplay-front.c
@@ -0,0 +1,311 @@
1+/*
2+ * gdb-freeplay
3+ *
4+ * Freely replay a remote debug session logfile for GDB.
5+ *
6+ * Parts of gdb-freeplay are adapted from gdbreplay,
7+ * by Stu Grossman and Fred Fish.
8+ */
9+
10+#include "config.h"
11+#include <stdio.h>
12+#if HAVE_SYS_FILE_H
13+#include <sys/file.h>
14+#endif
15+#if HAVE_SIGNAL_H
16+#include <signal.h>
17+#endif
18+#include <ctype.h>
19+#if HAVE_FCNTL_H
20+#include <fcntl.h>
21+#endif
22+#if HAVE_ERRNO_H
23+#include <errno.h>
24+#endif
25+#ifdef HAVE_STDLIB_H
26+#include <stdlib.h>
27+#endif
28+#ifdef HAVE_STRING_H
29+#include <string.h>
30+#endif
31+#ifdef HAVE_UNISTD_H
32+#include <unistd.h>
33+#endif
34+#ifdef HAVE_NETINET_IN_H
35+#include <netinet/in.h>
36+#endif
37+#ifdef HAVE_SYS_SOCKET_H
38+#include <sys/socket.h>
39+#endif
40+#if HAVE_NETDB_H
41+#include <netdb.h>
42+#endif
43+#if HAVE_NETINET_TCP_H
44+#include <netinet/tcp.h>
45+#endif
46+#if HAVE_MALLOC_H
47+#include <malloc.h>
48+#endif
49+
50+#if USE_WIN32API
51+#include <winsock.h>
52+#endif
53+
54+#ifndef HAVE_SOCKLEN_T
55+typedef int socklen_t;
56+#endif
57+
58+/* Version information, from version.c. */
59+extern const char version[];
60+extern const char host_name[];
61+
62+/* Print the system error message for errno, and also mention STRING
63+ as the file name for which the error was encountered.
64+ Then return to command level. */
65+
66+static void
67+perror_with_name (char *string)
68+{
69+#ifndef STDC_HEADERS
70+ extern int errno;
71+#endif
72+ const char *err;
73+ char *combined;
74+
75+ err = strerror (errno);
76+ if (err == NULL)
77+ err = "unknown error";
78+
79+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
80+ strcpy (combined, string);
81+ strcat (combined, ": ");
82+ strcat (combined, err);
83+ fprintf (stderr, "\n%s.\n", combined);
84+ fflush (stderr);
85+ exit (1);
86+}
87+
88+/*
89+ * remote_close
90+ *
91+ * Close the gdb socket.
92+ */
93+
94+static void
95+remote_close (int remote_desc)
96+{
97+#ifdef USE_WIN32API
98+ closesocket (remote_desc);
99+#else
100+ close (remote_desc);
101+#endif
102+}
103+
104+/*
105+ * remote_open
106+ *
107+ * Open a connection to a remote debugger (gdb).
108+ * NAME is the filename used for communication.
109+ *
110+ * Returns: file descriptor.
111+ * Does not return in case of error.
112+ */
113+
114+static int
115+remote_open (char *name)
116+{
117+ int remote_desc;
118+
119+ if (!strchr (name, ':'))
120+ {
121+ fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
122+ fflush (stderr);
123+ exit (1);
124+ }
125+ else
126+ {
127+#ifdef USE_WIN32API
128+ static int winsock_initialized;
129+#endif
130+ char *port_str;
131+ int port;
132+ struct sockaddr_in sockaddr;
133+ socklen_t tmp;
134+ int tmp_desc;
135+
136+ port_str = strchr (name, ':');
137+
138+ port = atoi (port_str + 1);
139+
140+#ifdef USE_WIN32API
141+ if (!winsock_initialized)
142+ {
143+ WSADATA wsad;
144+
145+ WSAStartup (MAKEWORD (1, 0), &wsad);
146+ winsock_initialized = 1;
147+ }
148+#endif
149+
150+ tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
151+ if (tmp_desc < 0)
152+ perror_with_name ("Can't open socket");
153+
154+ /* Allow rapid reuse of this port. */
155+ tmp = 1;
156+ setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
157+ sizeof (tmp));
158+
159+ sockaddr.sin_family = PF_INET;
160+ sockaddr.sin_port = htons (port);
161+ sockaddr.sin_addr.s_addr = INADDR_ANY;
162+
163+ if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
164+ || listen (tmp_desc, 1))
165+ perror_with_name ("Can't bind address");
166+
167+ tmp = sizeof (sockaddr);
168+ remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
169+ if (remote_desc == -1)
170+ perror_with_name ("Accept failed");
171+
172+ /* Enable TCP keep alive process. */
173+ tmp = 1;
174+ setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
175+
176+ /* Tell TCP not to delay small packets. This greatly speeds up
177+ interactive response. */
178+ tmp = 1;
179+ setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
180+ (char *) &tmp, sizeof (tmp));
181+
182+#ifndef USE_WIN32API
183+ close (tmp_desc); /* No longer need this */
184+
185+ signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
186+ exits when the remote side dies. */
187+#else
188+ closesocket (tmp_desc); /* No longer need this */
189+#endif
190+ }
191+
192+#if defined(F_SETFL) && defined (FASYNC)
193+ fcntl (remote_desc, F_SETFL, FASYNC);
194+#endif
195+
196+ fprintf (stderr, "Replay logfile using %s\n", name);
197+ fflush (stderr);
198+
199+ return remote_desc;
200+}
201+
202+/*
203+ * freeplay_version
204+ *
205+ * Print version information.
206+ */
207+
208+static void
209+freeplay_version (FILE *stream)
210+{
211+ fprintf (stream, "GNU gdb-freeplay %s%s\n"
212+ "Copyright (C) 2008 Free Software Foundation, Inc.\n"
213+ "gdb-freeplay is free software, covered by the GNU General Public License.\n"
214+ "\n"
215+ "This gdb-freeplay was configured as \"%s\"\n",
216+ PKGVERSION, version, host_name);
217+}
218+
219+/*
220+ * freeplay_usage
221+ *
222+ * Print usage information.
223+ */
224+
225+static void
226+freeplay_usage (FILE *stream)
227+{
228+ fprintf (stream, "Usage:\tgdb-freeplay [--verbose] [--version] <logfile> <host:port>\n");
229+ if (REPORT_BUGS_TO[0] && stream == stdout)
230+ fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO);
231+}
232+
233+#include "gdbfreeplay.h"
234+
235+/*
236+ * TODO:
237+ *
238+ * Actually accept packets from gdb, with handshake where appropriate.
239+ * Parse tfind requests and handle them in the frame cache.
240+ * Try to match everything else from the frame cache and send cached reply.
241+ */
242+
243+int verbose;
244+
245+extern int
246+main (int argc, char **argv)
247+{
248+ char *default_socket = "localhost:2345";
249+ int logfile_arg = 1;
250+ int socket_arg = 2;
251+ int remote_desc = -1, i;
252+
253+ for (i = 0; i < argc; i++)
254+ {
255+ if (strcmp (argv[i], "--version") == 0)
256+ {
257+ freeplay_version (stdout);
258+ logfile_arg++;
259+ socket_arg++;
260+ }
261+ if (strcmp (argv[i], "--verbose") == 0)
262+ {
263+ verbose = 1;
264+ logfile_arg++;
265+ socket_arg++;
266+ }
267+ else if (strcmp (argv[i], "--help") == 0)
268+ {
269+ freeplay_usage (stdout);
270+ exit (0);
271+ }
272+ else if (i == logfile_arg)
273+ {
274+ if (gdbfreeplay_open (argv[i]) != PASS)
275+ perror_with_name (argv[1]);
276+ logfile_arg = 0;
277+ }
278+ else if (i == socket_arg)
279+ {
280+ if (verbose)
281+ fprintf (stdout, "Open socket: %s\n", argv[i]);
282+ remote_desc = remote_open (argv[i]);
283+ socket_arg = 0;
284+ }
285+ }
286+
287+ if (logfile_arg)
288+ {
289+ freeplay_usage (stderr);
290+ exit (1);
291+ }
292+
293+ if (socket_arg)
294+ {
295+ if (verbose)
296+ fprintf (stdout, "Open default socket: %s\n", default_socket);
297+ remote_desc = remote_open (default_socket);
298+ }
299+
300+ if (remote_desc > 0)
301+ {
302+ gdbfreeplay (remote_desc);
303+
304+ if (verbose)
305+ fprintf (stdout, "Close remote socket.\n");
306+ remote_close (remote_desc);
307+ }
308+
309+ exit (0);
310+}
311+
--- /dev/null
+++ b/gdb/gdbserver/gdbfreeplay-i386.c
@@ -0,0 +1,334 @@
1+/*
2+ * gdbfreeplay-i386.c
3+ *
4+ * Target-dependent component of gdbfreeplay for i386.
5+ */
6+
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+
11+#include "gdbfreeplay.h"
12+
13+/*
14+ * Utility functions
15+ */
16+
17+/*
18+ * ix86_hex_to_unsigned_long
19+ *
20+ * Convert target-order ascii bytes to host unsigned long.
21+ * Returns host unsigned long.
22+ */
23+
24+static unsigned long
25+ix86_hex_to_unsigned_long (char *hex)
26+{
27+ unsigned long ul;
28+ int i;
29+
30+ for (i = 6; i >= 0; i-=2)
31+ {
32+ ul <<= 8;
33+ ul += hex_to_int (hex[i]) << 4;
34+ ul += hex_to_int (hex[i+1]);
35+ }
36+ return ul;
37+}
38+
39+/*
40+ * nybble_to_char
41+ */
42+
43+static char
44+nybble_to_char (int nybble)
45+{
46+ if (nybble < 10)
47+ return '0' + nybble;
48+ else
49+ return 'a' + (nybble - 10);
50+}
51+
52+/*
53+ * ix86_unsigned_long_to_hex
54+ *
55+ * Convert host unsigned long to target-order ascii string.
56+ * Return char buffer, static, use before calling again.
57+ */
58+
59+static char *
60+ix86_unsigned_long_to_hex (unsigned long value)
61+{
62+ int i;
63+ static char buf[16];
64+ char *p;
65+
66+ p = buf;
67+ for (i = 0; i < 4; i++)
68+ {
69+ /* Intel byte order. */
70+ *p++ = nybble_to_char ((value >> 4) & 0xf);
71+ *p++ = nybble_to_char (value & 0xf);
72+ value >>= 8;
73+ }
74+ *p = '\0';
75+ return buf;
76+}
77+
78+/*
79+ * target_pc_from_T
80+ *
81+ * Extract the PC value from the gdb protocol 'T' packet.
82+ * Returns PC as host unsigned long.
83+ */
84+
85+unsigned long
86+target_pc_from_T (char *tpacket)
87+{
88+ char *p;
89+
90+ if (tpacket[0] == '$' && tpacket[1] == 'T' &&
91+ (p = strstr (tpacket, ";08:")) != NULL)
92+ {
93+ return ix86_hex_to_unsigned_long (p + 4);
94+ }
95+
96+ /* Fail -- just assume no legitimate PC will ever be -1... */
97+ return (unsigned long) -1;
98+}
99+
100+/*
101+ * ix86_pc_from_registers
102+ *
103+ * Extract the PC value from a gdb protocol registers file.
104+ * Returns PC as host unsigned long.
105+ */
106+
107+static unsigned long
108+ix86_pc_from_registers (char *regs)
109+{
110+ return ix86_hex_to_unsigned_long (regs + 64);
111+}
112+
113+/*
114+ * target_pc_from_G
115+ *
116+ * Extract the PC value from the gdb protocol 'G' packet.
117+ * Returns PC as host unsigned long.
118+ */
119+
120+unsigned long
121+target_pc_from_G (char *gpacket)
122+{
123+ if (gpacket[0] == '$' && gpacket[1] == 'G')
124+ {
125+ return ix86_pc_from_registers (gpacket + 2);
126+ }
127+
128+ /* Fail -- just assume no legitimate PC will ever be -1... */
129+ return (unsigned long) -1;
130+}
131+
132+/*
133+ * expand_rle
134+ *
135+ * Stubs sometimes send us data with RLE compression.
136+ * FIXME this code is generic, move into gdbfreeplay-back.c
137+ * The code for this function lifted from gdb.
138+ */
139+
140+static char *
141+expand_rle (char *input)
142+{
143+ static char *buf = NULL;
144+ static int sizeof_buf;
145+ long bc = 0;
146+ int c, repeat;
147+
148+ /* Allocate buf on first time thru. */
149+ if (buf == NULL)
150+ {
151+ sizeof_buf = 4096;
152+ buf = realloc (buf, sizeof_buf);
153+ }
154+
155+ while (1)
156+ {
157+ c = *input++;
158+ switch (c) {
159+ case '#': /* End of interesting data. We don't care about checksum. */
160+ case '\0':/* End of string data. */
161+ buf[bc] = '\0';
162+ return buf;
163+ break;
164+ case '$':
165+ /* Shouldn't happen, but... */
166+ fprintf (stderr, "Warning: expand_rle saw '$' in middle of packet.\n");
167+ default:
168+ if (bc >= sizeof_buf - 1)
169+ {
170+ /* Make some more room in the buffer. */
171+ sizeof_buf *= 2;
172+ buf = realloc (buf, sizeof_buf);
173+ }
174+ buf[bc++] = c;
175+ continue;
176+ break;
177+ case '*': /* Run length encoding. */
178+ c = *input++;
179+ repeat = c - ' ' + 3; /* Compute repeat count. */
180+
181+ /* The character before '*' is repeated. */
182+ if (bc + repeat - 1 >= sizeof_buf - 1)
183+ {
184+ /* Make some more room in the buffer. */
185+ sizeof_buf *= 2;
186+ buf = realloc (buf, sizeof_buf);
187+ }
188+
189+ memset (&buf[bc], buf[bc - 1], repeat);
190+ bc += repeat;
191+ continue;
192+ break;
193+ }
194+ }
195+}
196+
197+/*
198+ * target_pc_from_g
199+ *
200+ * Extract the PC value from the gdb protocol 'g' packet reply.
201+ *
202+ * Unlike the two above, this function accepts a FILE pointer
203+ * rather than a char pointer, and must read data from the file.
204+ * FIXME I could make it like the others for symmetry...
205+ *
206+ * Returns PC as host unsigned long.
207+ */
208+
209+#define INBUF_SIZE 1024
210+static char inbuf [INBUF_SIZE];
211+
212+unsigned long
213+target_pc_from_g (FILE *infile)
214+{
215+ char *line = fgets (inbuf, sizeof (inbuf), infile);
216+
217+ if (line[0] == 'r' && line[1] == ' ')
218+ {
219+ line += 2;
220+ if (line[0] == '+')
221+ line++;
222+ if (line[0] == '$')
223+ line++;
224+ }
225+
226+ return ix86_pc_from_registers (expand_rle (line));
227+}
228+
229+/*
230+ * target_compose_T_packet
231+ *
232+ * On targets where DECR_PC_AFTER_BREAK is zero, this is a no-op.
233+ * We just send back the T packet that was sent to us.
234+ *
235+ * On targets like i386, where DECR_PC_AFTER_BREAK is non-zero,
236+ * it gets complicated. We have two pieces of information:
237+ *
238+ * 1) The address of the current instruction, and
239+ * 2) Whether we arrived at the current instruction
240+ * by virtue of a breakpoint -- ie. whether gdb is
241+ * expecting the PC to be off-by-one.
242+ *
243+ * Based on that info, we decide whether the T packet that was
244+ * sent to us is suitable as it is, or else we compose one and
245+ * send it back.
246+ *
247+ * Returns a string T packet, possibly WITHOUT CHECKSUM.
248+ * We leave it to the caller to handle that, if necessary,
249+ * because it is target independent and therefore inappropriate
250+ * to do here. However the caller has to check for it, because
251+ * if we simply return the T packet that we received, it will
252+ * already have a checksum.
253+ */
254+
255+char *
256+target_compose_T_packet (char *origTpacket,
257+ unsigned long instruction_pc,
258+ int breakpoint_p)
259+{
260+ unsigned long origTpacket_pc = target_pc_from_T (origTpacket);
261+ static char reply_buf[128];
262+ char *p;
263+
264+ /* There are four possibilities.
265+ 1) We got here by stepping, and instruction_pc == origTpacket_pc.
266+ 2) We got here by stepping, and instruction_pc != origTpacket_pc.
267+ 3) We got here by breakpoint, and instruction_pc == origTpacket_pc.
268+ 4) We got here by breakpoint, and instruction_pc != origTpacket_pc.
269+
270+ Actually, there's one more (not well understood):
271+ 5) instruction_pc and origTpacket_pc bear no relationship to each other.
272+
273+ In that case, we should bail and let gdb get the original Tpacket. */
274+
275+ /* Case #5. */
276+ if (instruction_pc != origTpacket_pc &&
277+ instruction_pc != origTpacket_pc - 1)
278+ return origTpacket;
279+
280+ /* For #1 and #4, we don't have to do anything, and can return
281+ the original T packet. */
282+
283+ /* Case #1. */
284+ if (!breakpoint_p && (instruction_pc == origTpacket_pc))
285+ return origTpacket;
286+
287+ /* Case #4. */
288+ if (breakpoint_p && (instruction_pc == origTpacket_pc - 1))
289+ return origTpacket;
290+
291+ /* That's it for the easy cases. For the other two, we have work to do.
292+ Start by making a copy of the original T packet. */
293+
294+ strcpy (reply_buf, origTpacket);
295+ if ((p = strstr (reply_buf, ";08:")) != NULL)
296+ {
297+#if 0
298+ /* Snip off the PC value from the original T packet. */
299+ p[4] = '\0';
300+ /* Case #2. */
301+ if (breakpoint_p)
302+ {
303+ /* Compose a T packet using instruction_pc + 1. */
304+ strcat (p, ix86_unsigned_long_to_hex (instruction_pc + 1));
305+ }
306+ else
307+ {
308+ /* Compose a T packet using instruction_pc. */
309+ strcat (p, ix86_unsigned_long_to_hex (instruction_pc));
310+ }
311+#else
312+ /* Insert the new PC value in place
313+ (without disturbing whatever follows it). */
314+
315+ /* Case #2. */
316+ if (breakpoint_p)
317+ {
318+ /* Compose a T packet using instruction_pc + 1. */
319+ memcpy (p + 4,
320+ ix86_unsigned_long_to_hex (instruction_pc + 1),
321+ 8);
322+ }
323+ else
324+ {
325+ /* Compose a T packet using instruction_pc. */
326+ memcpy (p + 4,
327+ ix86_unsigned_long_to_hex (instruction_pc),
328+ 8);
329+ }
330+#endif
331+ /* Caller has to recompute checksum. */
332+ return reply_buf;
333+ }
334+}
--- /dev/null
+++ b/gdb/gdbserver/gdbfreeplay.h
@@ -0,0 +1,21 @@
1+/*
2+ * gdbfreeplay -- interface
3+ */
4+
5+#ifndef GDBFREEPLAY_H
6+#define GDBFREEPLAY_H
7+
8+#include "remote-breakpoint.h"
9+
10+extern int verbose;
11+
12+extern enum successcode gdbfreeplay_open (char *filename);
13+extern void gdbfreeplay (int socket_fd);
14+
15+extern unsigned long target_pc_from_T (char *tpacket);
16+extern unsigned long target_pc_from_G (char *gpacket);
17+extern unsigned long target_pc_from_g (FILE *infile);
18+
19+extern int hex_to_int (int ch);
20+
21+#endif
--- /dev/null
+++ b/gdb/gdbserver/remote-breakpoint.c
@@ -0,0 +1,159 @@
1+/*
2+ * remote-breakpoint.c
3+ *
4+ * A breakpoint list for a remote gdb target.
5+ */
6+
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <ctype.h>
10+#include <string.h>
11+
12+#include "remote-breakpoint.h"
13+
14+static breakpoint *bplist[5];
15+
16+extern int verbose;
17+
18+/*
19+ * insert_breakpoint
20+ *
21+ * returns: FAIL/PASS
22+ */
23+
24+static enum successcode
25+insert_breakpoint (enum breakpoint_type bptype,
26+ unsigned long addr,
27+ unsigned long len)
28+{
29+ breakpoint *this_bp;
30+
31+ switch (bptype) {
32+ case ACCESS_BP:
33+ case HARDWARE_BP:
34+ case READ_BP:
35+ case WRITE_BP:
36+ default:
37+ /* Can't do those. */
38+ return FAIL;
39+ break;
40+ case SOFTWARE_BP:
41+ this_bp = malloc (sizeof (breakpoint));
42+ this_bp->addr = addr;
43+ this_bp->len = len;
44+ this_bp->next = bplist[bptype];
45+ bplist[bptype] = this_bp;
46+ return PASS;
47+ }
48+}
49+
50+/*
51+ * unlink_breakpoint
52+ *
53+ * returns: 0 for fail, 1 for success
54+ */
55+
56+static int
57+unlink_breakpoint (enum breakpoint_type bptype,
58+ unsigned long addr,
59+ unsigned long len)
60+{
61+ breakpoint *this_bp, *tmp;
62+
63+ switch (bptype) {
64+ case ACCESS_BP:
65+ case HARDWARE_BP:
66+ case READ_BP:
67+ case WRITE_BP:
68+ default:
69+ /* Can't do those. */
70+ return FAIL;
71+ break;
72+ case SOFTWARE_BP:
73+ /* Special case - list is empty. */
74+ if (bplist[bptype] == NULL)
75+ return FAIL;
76+
77+ /* Start from list head. */
78+ this_bp = bplist[bptype];
79+ /* Special case -- remove head of list. */
80+ if (this_bp->addr == addr &&
81+ this_bp->len == len)
82+ {
83+ bplist[bptype] = this_bp->next;
84+ return PASS;
85+ }
86+
87+ /* Scan list. */
88+ for (; this_bp && this_bp->next; this_bp = this_bp->next)
89+ if (this_bp->next->addr == addr &&
90+ this_bp->next->len == len)
91+ {
92+ /* Remove from middle of list. */
93+ tmp = this_bp->next->next;
94+ free (this_bp->next);
95+ this_bp->next = tmp;
96+ return PASS;
97+ }
98+
99+ /* Not found. */
100+ return FAIL;
101+ }
102+}
103+
104+
105+extern enum successcode
106+remote_remove_breakpoint (enum breakpoint_type bptype,
107+ unsigned long addr,
108+ unsigned long len)
109+{
110+ if (verbose)
111+ fprintf (stdout, "remote-breakpoint: Remove sw breakpoint type %d\n",
112+ bptype);
113+ if (unlink_breakpoint (bptype, addr, len) == 0)
114+ {
115+ fprintf (stderr, " FAILED!\n");
116+ return FAIL;
117+ }
118+ return PASS;
119+}
120+
121+extern enum successcode
122+remote_set_breakpoint (enum breakpoint_type bptype,
123+ unsigned long addr,
124+ unsigned long len)
125+{
126+ if (verbose)
127+ fprintf (stdout, "remote-breakpoint: Set sw breakpoint type %d\n",
128+ bptype);
129+ if (insert_breakpoint (bptype, addr, len) == 0)
130+ {
131+ fprintf (stderr, " FAILED!\n");
132+ return FAIL;
133+ }
134+ return PASS;
135+}
136+
137+/*
138+ * remote_breakpoint_here_p
139+ *
140+ * Scan the list of breakpoints of type BPTYPE.
141+ * Return PASS if there is one that matches ADDR, else FAIL.
142+ *
143+ * FIXME: do I need to consider the length?
144+ */
145+
146+enum successcode
147+remote_breakpoint_here_p (enum breakpoint_type bptype,
148+ unsigned long addr)
149+{
150+ breakpoint *bp = bplist[bptype];
151+
152+ while (bp != NULL)
153+ {
154+ if (bp->addr == addr)
155+ return PASS;
156+ bp = bp->next;
157+ }
158+ return FAIL;
159+}
--- /dev/null
+++ b/gdb/gdbserver/remote-breakpoint.h
@@ -0,0 +1,44 @@
1+/*
2+ * remote-breakpoint -- interface
3+ */
4+
5+#ifndef REMOTE_BREAKPOINT_H
6+#define REMOTE_BREAKPOINT_H
7+
8+typedef struct BREAKPOINT {
9+ unsigned long addr;
10+ unsigned long len;
11+ struct BREAKPOINT *next;
12+} breakpoint;
13+
14+enum breakpoint_type {
15+ SOFTWARE_BP,
16+ HARDWARE_BP,
17+ WRITE_BP,
18+ READ_BP,
19+ ACCESS_BP
20+};
21+
22+enum successcode {
23+ FAIL = 0,
24+ PASS = 1
25+};
26+
27+enum direction_code {
28+ DIR_FORWARD = 0,
29+ DIR_BACKWARD
30+};
31+
32+extern enum successcode remote_remove_breakpoint (enum breakpoint_type,
33+ unsigned long,
34+ unsigned long);
35+
36+extern enum successcode remote_set_breakpoint (enum breakpoint_type,
37+ unsigned long,
38+ unsigned long);
39+
40+extern enum successcode remote_breakpoint_here_p (enum breakpoint_type,
41+ unsigned long);
42+
43+#endif
44+