From: Michael Snyder <msnyder@vmware.com>
To: Hui Zhu <teawater@gmail.com>
Cc: Eli Zaretskii <eliz@gnu.org>,
"gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Subject: Re: [RFA/RFC] Add dump and load command to process record and replay
Date: Wed, 05 Aug 2009 21:23:00 -0000 [thread overview]
Message-ID: <4A79F802.4060102@vmware.com> (raw)
In-Reply-To: <daef60380908050220y3b15e8edo7b1a2525fea36dbb@mail.gmail.com>
Hui Zhu wrote:
> +static void
> +cmd_record_fd_cleanups (void *recfdp)
> +{
> + int recfd = *(int *) recfdp;
> + close (recfd);
> +}
Here's a suggested comment to start documenting the file format:
/* Record log save-file format
Version 1
Header:
4 bytes: magic number RECORD_FILE_MAGIC.
NOTE: be sure to change whenever this file format changes!
Records:
record_end:
1 byte: record type (record_end)
record_reg:
1 byte: record type (record_reg)
8 bytes: register id
16 bytes: register value
record_mem:
1 byte: record type (record_mem)
8 bytes: memory address
8 bytes: memory length
n bytes: memory value (n == memory length)
Version 2 (proposed)
[...] */
Below I'll suggest some possible debugging printfs.
Feel free to modify them to your own liking.
> +static inline void
> +record_read_dump (char *recfilename, int fildes, void *buf, size_t nbyte)
> +{
> + if (read (fildes, buf, nbyte) != nbyte)
> + error (_("Failed to read dump of execution records in '%s'."),
> + recfilename);
> +}
> +
> +static inline void
> +record_write_dump (char *recfilename, int fildes, const void *buf,
> + size_t nbyte)
> +{
> + if (write (fildes, buf, nbyte) != nbyte)
> + error (_("Failed to write dump of execution records to '%s'."),
> + recfilename);
> +}
> +
> +/* Dump the execution log to a file. */
> +
> +static void
> +cmd_record_dump (char *args, int from_tty)
> +{
> + char *recfilename, recfilename_buffer[40];
> + int recfd;
> + struct record_entry *cur_record_list;
> + uint32_t magic;
> + struct regcache *regcache;
> + struct gdbarch *gdbarch;
> + struct cleanup *old_cleanups;
> + struct cleanup *set_cleanups;
> +
> + if (current_target.to_stratum != record_stratum)
> + error (_("Process record is not started.\n"));
> +
> + if (args && *args)
> + recfilename = args;
> + else
> + {
> + /* Default corefile name is "gdb_record.PID". */
> + sprintf (recfilename_buffer, "gdb_record.%d", PIDGET (inferior_ptid));
> + recfilename = recfilename_buffer;
> + }
> +
> + /* Open the dump file. */
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
_("Saving recording to file '%s'\n"),
recfilename);
> + recfd = open (recfilename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
> + S_IRUSR | S_IWUSR);
> + if (recfd < 0)
> + error (_("Failed to open '%s' for dump execution records: %s"),
> + recfilename, strerror (errno));
> + old_cleanups = make_cleanup (cmd_record_fd_cleanups, &recfd);
> +
> + /* Save the current record entry to "cur_record_list". */
> + cur_record_list = record_list;
> +
> + /* Get the values of regcache and gdbarch. */
> + regcache = get_current_regcache ();
> + gdbarch = get_regcache_arch (regcache);
> +
> + /* Disable the GDB operation record. */
> + set_cleanups = record_gdb_operation_disable_set ();
> +
> + /* Write the magic code. */
> + magic = RECORD_FILE_MAGIC;
if (record_debug)
fprintf_unfiltered (gdb_stdlog, _("\
Writing 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n"),
magic);
> + record_write_dump (recfilename, recfd, &magic, 4);
> +
> + /* Reverse execute to the begin of record list. */
> + while (1)
> + {
> + /* Check for beginning and end of log. */
> + if (record_list == &record_first)
> + break;
> +
> + record_exec_entry (regcache, gdbarch, record_list);
> +
> + if (record_list->prev)
> + record_list = record_list->prev;
> + }
> +
> + /* Dump the entries to recfd and forward execute to the end of
> + record list. */
> + while (1)
> + {
> + /* Dump entry. */
> + if (record_list != &record_first)
> + {
> + uint8_t tmpu8;
> + uint64_t tmpu64;
> +
> + tmpu8 = record_list->type;
> + record_write_dump (recfilename, recfd, &tmpu8, 1);
> +
> + switch (record_list->type)
> + {
> + case record_reg: /* reg */
> + tmpu64 = record_list->u.reg.num;
> + if (BYTE_ORDER == LITTLE_ENDIAN)
> + tmpu64 = bswap_64 (tmpu64);
if (record_debug)
fprintf_unfiltered (gdb_stdlog, _("\
Writing register %d val 0x%016llx (1 plus 8 plus %d bytes)\n"),
p->u.reg.num,
*(ULONGEST *) p->u.reg.val,
MAX_REGISTER_SIZE);
> + record_write_dump (recfilename, recfd, &tmpu64, 8);
> +
> + record_write_dump (recfilename, recfd, record_list->u.reg.val,
> + MAX_REGISTER_SIZE);
> + break;
> + case record_mem: /* mem */
> + if (!record_list->u.mem.mem_entry_not_accessible)
> + {
> + tmpu64 = record_list->u.mem.addr;
> + if (BYTE_ORDER == LITTLE_ENDIAN)
> + tmpu64 = bswap_64 (tmpu64);
if (record_debug)
fprintf_unfiltered (gdb_stdlog, _("\
Writing memory 0x%08x (1 plus 8 plus 8 bytes plus %d bytes)\n"),
(unsigned int) p->u.mem.addr,
p->u.mem.len);
> + record_write_dump (recfilename, recfd, &tmpu64, 8);
> +
> + tmpu64 = record_list->u.mem.len;
> + if (BYTE_ORDER == LITTLE_ENDIAN)
> + tmpu64 = bswap_64 (tmpu64);
> + record_write_dump (recfilename, recfd, &tmpu64, 8);
> +
> + record_write_dump (recfilename, recfd,
> + record_list->u.mem.val,
> + record_list->u.mem.len);
> + }
> + break;
case record_end:
/* FIXME: record the contents of record_end rec. */
if (record_debug)
fprintf_unfiltered (gdb_stdlog, _("\
Writing record_end (1 byte)\n"));
break;
> + }
> + }
> +
> + /* Execute entry. */
> + record_exec_entry (regcache, gdbarch, record_list);
> +
> + if (record_list->next)
> + record_list = record_list->next;
> + else
> + break;
> + }
> +
> + /* Reverse execute to cur_record_list. */
> + while (1)
> + {
> + /* Check for beginning and end of log. */
> + if (record_list == cur_record_list)
> + break;
> +
> + record_exec_entry (regcache, gdbarch, record_list);
> +
> + if (record_list->prev)
> + record_list = record_list->prev;
> + }
> +
> + do_cleanups (set_cleanups);
> + do_cleanups (old_cleanups);
> +
> + /* Succeeded. */
> + fprintf_filtered (gdb_stdout, _("Saved dump of execution "
> + "records to `%s'.\n"),
> + recfilename);
> +}
> +
> +/* Load the execution log from a file. */
> +
> +static void
> +cmd_record_load (char *args, int from_tty)
> +{
> + int recfd;
> + uint32_t magic;
> + struct cleanup *old_cleanups;
> + struct cleanup *old_cleanups2;
> + struct record_entry *rec;
> + int insn_number = 0;
> +
> + if (current_target.to_stratum != record_stratum)
> + {
> + cmd_record_start (NULL, from_tty);
> + printf_unfiltered (_("Auto start process record.\n"));
> + }
> +
> + if (!args || (args && !*args))
> + error (_("Argument for filename required.\n"));
> +
/* Open the load file. */
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
_("Restoring recording from file '%s'\n"), args);
> + /* Open the load file. */
> + recfd = open (args, O_RDONLY | O_BINARY);
> + if (recfd < 0)
> + error (_("Failed to open '%s' for loading execution records: %s"),
> + args, strerror (errno));
> + old_cleanups = make_cleanup (cmd_record_fd_cleanups, &recfd);
> +
> + /* Check the magic code. */
> + record_read_dump (args, recfd, &magic, 4);
> + if (magic != RECORD_FILE_MAGIC)
> + error (_("'%s' is not a valid dump of execution records."), args);
> +
> + /* Load the entries in recfd to the record_arch_list_head and
> + record_arch_list_tail. */
> + record_arch_list_head = NULL;
> + record_arch_list_tail = NULL;
> + old_cleanups2 = make_cleanup (record_arch_list_cleanups, 0);
> +
> + while (1)
> + {
> + int ret;
> + uint8_t tmpu8;
> + uint64_t tmpu64;
> +
> + ret = read (recfd, &tmpu8, 1);
> + if (ret < 0)
> + error (_("Failed to read dump of execution records in '%s'."), args);
> + if (ret == 0)
> + break;
> +
> + switch (tmpu8)
> + {
> + case record_reg: /* reg */
> + rec = (struct record_entry *) xmalloc (sizeof (struct record_entry));
> + rec->u.reg.val = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE);
> + rec->prev = NULL;
> + rec->next = NULL;
> + rec->type = record_reg;
> + /* Get num. */
> + record_read_dump (args, recfd, &tmpu64, 8);
> + if (BYTE_ORDER == LITTLE_ENDIAN)
> + tmpu64 = bswap_64 (tmpu64);
> + rec->u.reg.num = tmpu64;
> + /* Get val. */
> + record_read_dump (args, recfd, rec->u.reg.val, MAX_REGISTER_SIZE);
if (record_debug)
fprintf_unfiltered (gdb_stdlog, _("\
Reading register %d val 0x%016llx (1 plus 8 plus %d bytes)\n"),
rec->u.reg.num,
*(ULONGEST *) rec->u.reg.val,
MAX_REGISTER_SIZE);
> + record_arch_list_add (rec);
> + break;
> + case record_mem: /* mem */
> + rec = (struct record_entry *) xmalloc (sizeof (struct record_entry));
> + rec->prev = NULL;
> + rec->next = NULL;
> + rec->type = record_mem;
> + /* Get addr. */
> + record_read_dump (args, recfd, &tmpu64, 8);
> + if (BYTE_ORDER == LITTLE_ENDIAN)
> + tmpu64 = bswap_64 (tmpu64);
> + rec->u.mem.addr = tmpu64;
> + /* Get len. */
> + record_read_dump (args, recfd, &tmpu64, 8);
> + if (BYTE_ORDER == LITTLE_ENDIAN)
> + tmpu64 = bswap_64 (tmpu64);
> + rec->u.mem.len = tmpu64;
> + rec->u.mem.mem_entry_not_accessible = 0;
> + rec->u.mem.val = (gdb_byte *) xmalloc (rec->u.mem.len);
> + /* Get val. */
> + record_read_dump (args, recfd, rec->u.mem.val, rec->u.mem.len);
if (record_debug)
fprintf_unfiltered (gdb_stdlog, _("\
Reading memory 0x%08x (1 plus 8 plus %d bytes)\n"),
(unsigned int) rec->u.mem.addr,
rec->u.mem.len);
> + record_arch_list_add (rec);
> + break;
> +
> + case record_end: /* end */
> + rec = (struct record_entry *) xmalloc (sizeof (struct record_entry));
> + rec->prev = NULL;
> + rec->next = NULL;
> + rec->type = record_end;
if (record_debug)
fprintf_unfiltered (gdb_stdlog, _("\
Reading record_end (one byte)\n"));
> + record_arch_list_add (rec);
> + insn_number ++;
> + break;
> +
> + default:
> + error (_("Format of '%s' is not right."), args);
> + break;
> + }
> + }
> +
> + discard_cleanups (old_cleanups2);
> +
> + /* Add record_arch_list_head to the end of record list. */
> + for (rec = record_list; rec->next; rec = rec->next);
> + rec->next = record_arch_list_head;
> + record_arch_list_head->prev = rec;
> +
> + /* Update record_insn_num and record_insn_max_num. */
> + record_insn_num += insn_number;
> + if (record_insn_num > record_insn_max_num)
> + {
> + record_insn_max_num = record_insn_num;
> + warning (_("Auto increase record/replay buffer limit to %d."),
> + record_insn_max_num);
> + }
> +
> + do_cleanups (old_cleanups);
> +
> + /* Succeeded. */
> + fprintf_filtered (gdb_stdout, "Loaded recfile %s.\n", args);
> +}
> +
next prev parent reply other threads:[~2009-08-05 21:23 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-01 7:31 Hui Zhu
2009-08-01 9:57 ` Eli Zaretskii
2009-08-01 19:20 ` Michael Snyder
2009-08-02 3:18 ` Michael Snyder
2009-08-02 5:58 ` Hui Zhu
2009-08-03 4:12 ` Hui Zhu
2009-08-03 18:29 ` Eli Zaretskii
2009-08-04 1:58 ` Hui Zhu
2009-08-04 2:07 ` Hui Zhu
2009-08-04 18:26 ` Eli Zaretskii
2009-08-04 20:01 ` Michael Snyder
2009-08-05 9:21 ` Hui Zhu
2009-08-05 20:19 ` [RFA/RFC] Add dump and load command to process record (file format etc) Michael Snyder
2009-08-06 2:17 ` Hui Zhu
2009-08-12 14:11 ` Michael Snyder
2009-08-12 15:16 ` Tom Tromey
2009-08-12 22:38 ` Michael Snyder
2009-08-16 0:04 ` Hui Zhu
2009-08-05 21:23 ` Michael Snyder [this message]
2009-08-06 3:14 ` [RFA/RFC] Add dump and load command to process record and replay Eli Zaretskii
2009-08-06 14:16 ` Hui Zhu
2009-08-07 3:27 ` Michael Snyder
2009-08-07 3:29 ` Hui Zhu
2009-08-07 3:34 ` Michael Snyder
2009-08-07 4:06 ` Hui Zhu
2009-08-07 8:41 ` Eli Zaretskii
2009-08-07 9:53 ` Hui Zhu
2009-08-07 12:51 ` Eli Zaretskii
2009-08-07 16:22 ` Hui Zhu
2009-08-07 17:42 ` Michael Snyder
2009-08-08 13:28 ` Hui Zhu
2009-08-10 3:09 ` Michael Snyder
2009-08-22 17:39 ` Hui Zhu
2009-08-23 1:14 ` Hui Zhu
2009-08-23 23:43 ` Michael Snyder
2009-08-24 8:20 ` Hui Zhu
2009-08-24 18:32 ` Michael Snyder
2009-08-25 8:47 ` Hui Zhu
2009-08-26 1:40 ` Michael Snyder
2009-08-26 2:59 ` Michael Snyder
2009-08-29 15:53 ` Hui Zhu
2009-08-29 18:06 ` Eli Zaretskii
2009-08-29 18:28 ` Hui Zhu
2009-08-29 20:26 ` Eli Zaretskii
2009-08-29 20:39 ` Michael Snyder
2009-08-30 3:03 ` Eli Zaretskii
2009-08-30 5:36 ` Hui Zhu
2009-08-30 23:40 ` Eli Zaretskii
2009-08-31 7:10 ` Hui Zhu
2009-09-05 3:30 ` Michael Snyder
2009-09-06 16:29 ` Hui Zhu
2009-08-29 20:05 ` Michael Snyder
2009-08-29 20:33 ` Eli Zaretskii
2009-08-29 21:20 ` Michael Snyder
2022-01-21 6:46 Simon Sobisch via Gdb-patches
2022-01-24 9:26 ` Hui Zhu via Gdb-patches
2022-04-13 12:21 ` Simon Sobisch via Gdb-patches
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A79F802.4060102@vmware.com \
--to=msnyder@vmware.com \
--cc=eliz@gnu.org \
--cc=gdb-patches@sourceware.org \
--cc=teawater@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox