This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA, 3 of 3] save/restore process record, part 3 (save/restore)


Hi Michael,

Thanks for your patch.

I cannot find the diff for the gcore.c file.

       (netorder64): New function.
       (netorder32): New function.
       (netorder16): New function.

I suggest inline them.

Thanks,
Hui

On Sun, Oct 18, 2009 at 06:13, Michael Snyder <msnyder@vmware.com> wrote:
> Eli Zaretskii wrote:
>>>
>>> Date: Sat, 17 Oct 2009 11:36:35 -0700
>>> From: Michael Snyder <msnyder@vmware.com>
>>> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>,
>>> ?"teawater@gmail.com" <teawater@gmail.com>
>>>
>>>>> + ? ? ? NOTE: be sure to change whenever this file format changes!
>>>>> +
>>>>> + ? Records:
>>>>> + ? ? record_end:
>>>>> + ? ? ? 1 byte: ?record type (record_end).
>>>>
>>>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^^^^^^^^^^
>>>> This probably has some integer value, right? ?Or does this indicate
>>>> something other than an integer type?
>>>
>>> It's an enum. ?Why? ?You think I should give its numeric
>>> value in the comment, instead of its symbolic value?
>>
>> Either the numeric value or a more explicit reference to the enum
>> (e.g., say that it's an enum defined on such-and-such file).
>>
>> IOW, imagine that someone reads these comments because they want to
>> write a utility that reads these files, and ask yourself what would
>> they be missing in this text.
>
> OK, see revised patch.
>
>>>>> + ? ? record_reg:
>>>>> + ? ? ? 1 byte: ?record type (record_reg).
>>>>> + ? ? ? 4 bytes: register id (network byte order).
>>>>> + ? ? ? n bytes: register value (n == register size).
>>>>
>>>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^^^^^^^^^^^^^
>>>> How does one know what is the correct register size?
>>>
>>> We get it from the current regcache and regnum. ?What can I say about
>>> it here, that wouldn't be arch-specific?
>>
>> Well, saying it's the exact size of the register being recorded works
>> for me.
>
> OK.
>
>>
>>> I mean, I could say:
>>>
>>> ? ?This will generally be 4 bytes for x86, 8 bytes for x86_64.
>>
>> That's good as an example.
>>
>>> but that doesn't seem very useful or scalable. ?Plus it will
>>> be different for floating point regs, once we handle them too.
>>
>> Would it make sense to use here some size that can accommodate all the
>> known registers, to make the file format truly architecture
>> independent? ?Or would it be more trouble than it's worth?
>
> That's what version 1 of the file format did.
> I found it wasteful, hence this change.
>
>>
>>>>> + ?if (strcmp (current_target.to_shortname, "record") != 0)
>>>>> + ? ?error (_("Process record is not started.\n"));
>>>>
>>>> Suggest to add to the message text something that tells the user how
>>>> to remedy this situation. ?E.g., "Invoke FOO command first."
>>>
>>> OK. ?It's a target-specific command, that can only be used
>>> with target 'record'. ?How about this?
>>>
>>> ? error (_("This command can only be used with target 'record'.\n"));
>>
>> That's good, but maybe adding "Use 'record start' first." will be
>> better?
>
> OK.
>
>>
>>> This is the same approach that is used by the "gcore" command.
>>> How does "gcore" work with go32, if at all?
>>
>> It doesn't. ?DJGPP cannot generate core files.
>
> Well, save/restore depends on core files, so I guess
> it won't work in go32.
>
>
>>> Thanks for all your suggestions, Eli.
>>> Please see revised patch attached.
>>
>> It's fine, except for this:
>>
>>> + ? Header:
>>> + ? ? 4 bytes: magic number htonl(0x20090829).
>>
>> I thought you agreed to replace this with "0x20090829 (network byte
>> order)"?
>
> Ah. ?Yes -- you're looking at the version 1 header, but I do need
> to change the comment for the version 2 header.
>
> See revised patch below.
>
>
>
> 2009-10-16 ?Hui Zhu ?<teawater@gmail.com>
> ? ? ? ? ? ?Michael Snyder ?<msnyder@msnyder-server.eng.vmware.com>
>
> ? ? ? ?* record.c (RECORD_FILE_MAGIC): New constant.
> ? ? ? ?(record_arch_list_cleanups): Renamed from record_message_cleanups.
> ? ? ? ?(bfdcore_read): New function.
> ? ? ? ?(netorder64): New function.
> ? ? ? ?(netorder32): New function.
> ? ? ? ?(netorder16): New function.
> ? ? ? ?(record_restore): New function. ?Restore a saved record log.
> ? ? ? ?(bfdcore_write): New function.
> ? ? ? ?(cmd_record_restore): New function.
> ? ? ? ?(cmd_record_save): New function. ?Save a record log to a file.
> ? ? ? ?(_initialize_record): Set up commands for save and restore.
>
> --- record.2b.c 2009-10-17 11:30:35.000000000 -0700
> +++ record.12.c 2009-10-17 15:09:48.000000000 -0700
> @@ -23,10 +23,15 @@
> ?#include "gdbthread.h"
> ?#include "event-top.h"
> ?#include "exceptions.h"
> +#include "completer.h"
> +#include "arch-utils.h"
> ?#include "gdbcore.h"
> ?#include "exec.h"
> ?#include "record.h"
> +#include "elf-bfd.h"
> +#include "gcore.h"
>
> +#include <byteswap.h>
> ?#include <signal.h>
>
> ?#define DEFAULT_RECORD_INSN_MAX_NUM ? ?200000
> @@ -34,6 +39,8 @@
> ?#define RECORD_IS_REPLAY \
> ? ? ?(record_list->next || execution_direction == EXEC_REVERSE)
>
> +#define RECORD_FILE_MAGIC ? ? ?netorder32(0x20091016)
> +
> ?/* These are the core structs of the process record functionality.
>
> ? ?A record_entry is a record of the value change of a register
> @@ -482,24 +489,24 @@ record_check_insn_num (int set_terminal)
> ? ? ? ? ? ? ?if (q)
> ? ? ? ? ? ? ? ?record_stop_at_limit = 0;
> ? ? ? ? ? ? ?else
> - ? ? ? ? ? ? ? error (_("Process record: inferior program stopped."));
> + ? ? ? ? ? ? ? error (_("Process record: stopped by user."));
> ? ? ? ? ? ?}
> ? ? ? ?}
> ? ? }
> ?}
>
> +static void
> +record_arch_list_cleanups (void *ignore)
> +{
> + ?record_list_release (record_arch_list_tail);
> +}
> +
> ?/* Before inferior step (when GDB record the running message, inferior
> ? ?only can step), GDB will call this function to record the values to
> ? ?record_list. ?This function will call gdbarch_process_record to
> ? ?record the running message of inferior and set them to
> ? ?record_arch_list, and add it to record_list. ?*/
>
> -static void
> -record_message_cleanups (void *ignore)
> -{
> - ?record_list_release (record_arch_list_tail);
> -}
> -
> ?struct record_message_args {
> ? struct regcache *regcache;
> ? enum target_signal signal;
> @@ -511,7 +518,7 @@ record_message (void *args)
> ? int ret;
> ? struct record_message_args *myargs = args;
> ? struct gdbarch *gdbarch = get_regcache_arch (myargs->regcache);
> - ?struct cleanup *old_cleanups = make_cleanup (record_message_cleanups, 0);
> + ?struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups,
> 0);
>
> ? record_arch_list_head = NULL;
> ? record_arch_list_tail = NULL;
> @@ -651,8 +658,8 @@ record_exec_insn (struct regcache *regca
> ? ? ? ? ? ? ? {
> ? ? ? ? ? ? ? ? entry->u.mem.mem_entry_not_accessible = 1;
> ? ? ? ? ? ? ? ? if (record_debug)
> - ? ? ? ? ? ? ? ? ?warning (_("Process record: error reading memory at "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? "addr = %s len = %d."),
> + ? ? ? ? ? ? ? ? ?warning ("Process record: error reading memory at "
> + ? ? ? ? ? ? ? ? ? ? ? ? ?"addr = %s len = %d.",
> ? ? ? ? ? ? ? ? ? ? ? ? ? paddress (gdbarch, entry->u.mem.addr),
> ? ? ? ? ? ? ? ? ? ? ? ? ? ?entry->u.mem.len);
> ? ? ? ? ? ? ? }
> @@ -664,8 +671,8 @@ record_exec_insn (struct regcache *regca
> ? ? ? ? ? ? ? ? ? {
> ? ? ? ? ? ? ? ? ? ? entry->u.mem.mem_entry_not_accessible = 1;
> ? ? ? ? ? ? ? ? ? ? if (record_debug)
> - ? ? ? ? ? ? ? ? ? ? ?warning (_("Process record: error writing memory at "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "addr = %s len = %d."),
> + ? ? ? ? ? ? ? ? ? ? ?warning ("Process record: error writing memory at "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"addr = %s len = %d.",
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?paddress (gdbarch, entry->u.mem.addr),
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?entry->u.mem.len);
> ? ? ? ? ? ? ? ? ? }
> @@ -678,6 +685,215 @@ record_exec_insn (struct regcache *regca
> ? ? }
> ?}
>
> +/* bfdcore_read -- read bytes from a core file section. ?*/
> +
> +static void
> +bfdcore_read (bfd *obfd, asection *osec, void *buf, int len, int *offset)
> +{
> + ?int ret = bfd_get_section_contents (obfd, osec, buf, *offset, len);
> +
> + ?if (ret)
> + ? ?*offset += len;
> + ?else
> + ? ?error (_("Failed to read %d bytes from core file %s ('%s').\n"),
> + ? ? ? ? ?len, bfd_get_filename (obfd),
> + ? ? ? ? ?bfd_errmsg (bfd_get_error ()));
> +}
> +
> +static uint64_t
> +netorder64 (uint64_t fromfile)
> +{
> + ?return (BYTE_ORDER == LITTLE_ENDIAN)
> + ? ?? bswap_64 (fromfile)
> + ? ?: fromfile;
> +}
> +
> +static uint32_t
> +netorder32 (uint32_t fromfile)
> +{
> + ?return (BYTE_ORDER == LITTLE_ENDIAN)
> + ? ?? bswap_32 (fromfile)
> + ? ?: fromfile;
> +}
> +
> +static uint16_t
> +netorder16 (uint16_t fromfile)
> +{
> + ?return (BYTE_ORDER == LITTLE_ENDIAN)
> + ? ?? bswap_16 (fromfile)
> + ? ?: fromfile;
> +}
> +
> +/* Restore the execution log from a core_bfd file. ?*/
> +
> +static void
> +record_restore (void)
> +{
> + ?uint32_t magic;
> + ?struct cleanup *old_cleanups;
> + ?struct record_entry *rec;
> + ?asection *osec;
> + ?uint32_t osec_size;
> + ?int bfd_offset = 0;
> + ?struct regcache *regcache;
> +
> + ?/* We restore the execution log from the open core bfd,
> + ? ? if there is one. ?*/
> + ?if (core_bfd == NULL)
> + ? ?return;
> +
> + ?/* "record_restore" can only be called when record list is empty. ?*/
> + ?gdb_assert (record_first.next == NULL);
> +
> + ?if (record_debug)
> + ? ?printf_filtered ("Restoring recording from core file.\n");
> +
> + ?/* Now need to find our special note section. ?*/
> + ?osec = bfd_get_section_by_name (core_bfd, "null0");
> + ?osec_size = bfd_section_size (core_bfd, osec);
> + ?if (record_debug)
> + ? ?printf_filtered ("Find precord section %s.\n",
> + ? ? ? ? ? ? ? ? ? ?osec ? "succeeded" : "failed");
> + ?if (!osec)
> + ? ?return;
> + ?if (record_debug)
> + ? ?printf_filtered ("%s", bfd_section_name (core_bfd, osec));
> +
> + ?/* Check the magic code. ?*/
> + ?if (record_debug)
> + ? ?printf_filtered ("\
> + ?Reading 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n",
> + ? ? ? ? ? ? ? ? ? ?magic);
> + ?bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset);
> + ?if (magic != RECORD_FILE_MAGIC)
> + ? ?error (_("Version mis-match or file format error in core file %s."),
> + ? ? ? ? ?bfd_get_filename (core_bfd));
> +
> + ?/* Restore the entries in recfd into record_arch_list_head and
> + ? ? record_arch_list_tail. ?*/
> + ?record_arch_list_head = NULL;
> + ?record_arch_list_tail = NULL;
> + ?record_insn_num = 0;
> + ?old_cleanups = make_cleanup (record_arch_list_cleanups, 0);
> + ?regcache = get_current_regcache ();
> +
> + ?while (1)
> + ? ?{
> + ? ? ?int ret;
> + ? ? ?uint8_t tmpu8;
> + ? ? ?uint32_t regnum, len, signal, count;
> + ? ? ?uint64_t addr;
> +
> + ? ? ?/* We are finished when offset reaches osec_size. ?*/
> + ? ? ?if (bfd_offset >= osec_size)
> + ? ? ? break;
> + ? ? ?bfdcore_read (core_bfd, osec, &tmpu8, sizeof (tmpu8), &bfd_offset);
> +
> + ? ? ?switch (tmpu8)
> + ? ? ? ?{
> + ? ? ? ?case record_reg: /* reg */
> + ? ? ? ? ?if (record_debug)
> + ? ? ? ? ? ?printf_filtered ("\
> + ?Reading register %d (1 plus %d plus %d bytes)\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?rec->u.reg.num,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (regnum),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?rec->u.reg.len);
> + ? ? ? ? ?/* Get register number to regnum. ?*/
> + ? ? ? ? ?bfdcore_read (core_bfd, osec, &regnum,
> + ? ? ? ? ? ? ? ? ? ? ? sizeof (regnum), &bfd_offset);
> + ? ? ? ? regnum = netorder32 (regnum);
> +
> + ? ? ? ? ?rec = record_reg_alloc (regcache, regnum);
> +
> + ? ? ? ? ?/* Get val. ?*/
> + ? ? ? ? ?bfdcore_read (core_bfd, osec, record_get_loc (rec),
> + ? ? ? ? ? ? ? ? ? ? ? rec->u.reg.len, &bfd_offset);
> + ? ? ? ? ?break;
> +
> + ? ? ? ?case record_mem: /* mem */
> + ? ? ? ? ?if (record_debug)
> + ? ? ? ? ? ?printf_filtered ("\
> + ?Reading memory %s (1 plus %d plus %d plus %d bytes)\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?paddress (get_current_arch (),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?rec->u.mem.addr),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (addr),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (len),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?rec->u.mem.len);
> + ? ? ? ? ?/* Get len. ?*/
> + ? ? ? ? ?bfdcore_read (core_bfd, osec, &len,
> + ? ? ? ? ? ? ? ? ? ? ? sizeof (len), &bfd_offset);
> + ? ? ? ? len = netorder32 (len);
> +
> + ? ? ? ? ?/* Get addr. ?*/
> + ? ? ? ? ?bfdcore_read (core_bfd, osec, &addr,
> + ? ? ? ? ? ? ? ? ? ? ? sizeof (addr), &bfd_offset);
> + ? ? ? ? addr = netorder64 (addr);
> +
> + ? ? ? ? ?rec = record_mem_alloc (addr, len);
> +
> + ? ? ? ? ?/* Get val. ?*/
> + ? ? ? ? ?bfdcore_read (core_bfd, osec, record_get_loc (rec),
> + ? ? ? ? ? ? ? ? ? ? ? rec->u.mem.len, &bfd_offset);
> + ? ? ? ? ?break;
> +
> + ? ? ? ?case record_end: /* end */
> + ? ? ? ? ?if (record_debug)
> + ? ? ? ? ? ?printf_filtered ("\
> + ?Reading record_end (1 + %d + %d bytes), offset == %s\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (signal),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (count),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?paddress (get_current_arch (),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?bfd_offset));
> + ? ? ? ? ?rec = record_end_alloc ();
> + ? ? ? ? ?record_insn_num ++;
> +
> + ? ? ? ? /* Get signal value. ?*/
> + ? ? ? ? bfdcore_read (core_bfd, osec, &signal,
> + ? ? ? ? ? ? ? ? ? ? ? sizeof (signal), &bfd_offset);
> + ? ? ? ? signal = netorder32 (signal);
> + ? ? ? ? rec->u.end.sigval = signal;
> +
> + ? ? ? ? /* Get insn count. ?*/
> + ? ? ? ? bfdcore_read (core_bfd, osec, &count,
> + ? ? ? ? ? ? ? ? ? ? ? sizeof (count), &bfd_offset);
> + ? ? ? ? count = netorder32 (count);
> + ? ? ? ? rec->u.end.insn_num = count;
> + ? ? ? ? record_insn_count = count + 1;
> + ? ? ? ? ?break;
> +
> + ? ? ? ?default:
> + ? ? ? ? ?error (_("Bad entry type in core file %s."),
> + ? ? ? ? ? ? ? ?bfd_get_filename (core_bfd));
> + ? ? ? ? ?break;
> + ? ? ? ?}
> +
> + ? ? ?/* Add rec to record arch list. ?*/
> + ? ? ?record_arch_list_add (rec);
> + ? ?}
> +
> + ?discard_cleanups (old_cleanups);
> +
> + ?/* Add record_arch_list_head to the end of record list. ?*/
> + ?record_first.next = record_arch_list_head;
> + ?record_arch_list_head->prev = &record_first;
> + ?record_arch_list_tail->next = NULL;
> + ?record_list = &record_first;
> +
> + ?/* Update record_insn_max_num. ?*/
> + ?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);
> + ? ?}
> +
> + ?/* Succeeded. ?*/
> + ?printf_filtered (_("Restored records from core file %s.\n"),
> + ? ? ? ? ? ? ? ? ?bfd_get_filename (core_bfd));
> +
> + ?print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
> +}
> +
> ?static struct target_ops *tmp_to_resume_ops;
> ?static void (*tmp_to_resume) (struct target_ops *, ptid_t, int,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?enum target_signal);
> @@ -728,6 +944,7 @@ record_core_open_1 (char *name, int from
> ? ? }
>
> ? push_target (&record_core_ops);
> + ?record_restore ();
> ?}
>
> ?static void
> @@ -735,9 +952,6 @@ record_open_1 (char *name, int from_tty)
> ?{
> ? struct target_ops *t;
>
> - ?if (record_debug)
> - ? ?fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
> -
> ? /* check exec */
> ? if (!target_has_execution)
> ? ? error (_("Process record: the program is not being run."));
> @@ -779,6 +993,12 @@ record_open (char *name, int from_tty)
> ? ? error (_("Process record target already running. ?Use \"record stop\" to
> "
> ? ? ? ? ? ? ?"stop record target first."));
>
> + ?/* Reset */
> + ?record_insn_num = 0;
> + ?record_insn_count = 0;
> + ?record_list = &record_first;
> + ?record_list->next = NULL;
> +
> ? /* Reset the tmp beneath pointers. ?*/
> ? tmp_to_resume_ops = NULL;
> ? tmp_to_resume = NULL;
> @@ -822,17 +1042,6 @@ record_open (char *name, int from_tty)
> ? if (!tmp_to_xfer_partial)
> ? ? error (_("Could not find 'to_xfer_partial' method on the target
> stack."));
>
> - ?if (current_target.to_stratum == core_stratum)
> - ? ?record_core_open_1 (name, from_tty);
> - ?else
> - ? ?record_open_1 (name, from_tty);
> -
> - ?/* Reset */
> - ?record_insn_num = 0;
> - ?record_insn_count = 0;
> - ?record_list = &record_first;
> - ?record_list->next = NULL;
> -
> ? /* Set the tmp beneath pointers to beneath pointers. ?*/
> ? record_beneath_to_resume_ops = tmp_to_resume_ops;
> ? record_beneath_to_resume = tmp_to_resume;
> @@ -844,6 +1053,11 @@ record_open (char *name, int from_tty)
> ? record_beneath_to_xfer_partial = tmp_to_xfer_partial;
> ? record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
> ? record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
> +
> + ?if (current_target.to_stratum == core_stratum)
> + ? ?record_core_open_1 (name, from_tty);
> + ?else
> + ? ?record_open_1 (name, from_tty);
> ?}
>
> ?static void
> @@ -1114,8 +1328,7 @@ record_wait (struct target_ops *ops,
> ? ? ? ? ? ? ? ? ? ?{
> ? ? ? ? ? ? ? ? ? ? ?if (record_debug)
> ? ? ? ? ? ? ? ? ? ? ? ?fprintf_unfiltered (gdb_stdlog,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Process record: break "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "at %s.\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Process record: break at
> %s.\n",
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?paddress (gdbarch, tmp_pc));
> ? ? ? ? ? ? ? ? ? ? ?if (gdbarch_decr_pc_after_break (gdbarch)
> ? ? ? ? ? ? ? ? ? ? ? ? ?&& execution_direction == EXEC_FORWARD
> @@ -1190,8 +1403,7 @@ static void
> ?record_mourn_inferior (struct target_ops *ops)
> ?{
> ? if (record_debug)
> - ? ?fprintf_unfiltered (gdb_stdlog, "Process record: "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "record_mourn_inferior\n");
> + ? ?fprintf_unfiltered (gdb_stdlog, "Process record:
> record_mourn_inferior\n");
>
> ? unpush_target (&record_ops);
> ? target_mourn_inferior ();
> @@ -1345,8 +1557,8 @@ record_xfer_partial (struct target_ops *
> ? ? ? ? ?record_list_release (record_arch_list_tail);
> ? ? ? ? ?if (record_debug)
> ? ? ? ? ? ?fprintf_unfiltered (gdb_stdlog,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? _("Process record: failed to record "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "execution log."));
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Process record: failed to record "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "execution log.");
> ? ? ? ? ?return -1;
> ? ? ? ?}
> ? ? ? if (record_arch_list_add_end ())
> @@ -1354,8 +1566,8 @@ record_xfer_partial (struct target_ops *
> ? ? ? ? ?record_list_release (record_arch_list_tail);
> ? ? ? ? ?if (record_debug)
> ? ? ? ? ? ?fprintf_unfiltered (gdb_stdlog,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? _("Process record: failed to record "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "execution log."));
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Process record: failed to record "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "execution log.");
> ? ? ? ? ?return -1;
> ? ? ? ?}
> ? ? ? record_list->next = record_arch_list_head;
> @@ -1642,6 +1854,297 @@ cmd_record_start (char *args, int from_t
> ? execute_command ("target record", from_tty);
> ?}
>
> +/* Record log save-file format
> + ? Version 1 (never released)
> +
> + ? Header:
> + ? ? 4 bytes: magic number htonl(0x20090829).
> + ? ? ? NOTE: be sure to change whenever this file format changes!
> +
> + ? Records:
> + ? ? record_end:
> + ? ? ? 1 byte: ?record type (record_end, see enum record_type).
> + ? ? record_reg:
> + ? ? ? 1 byte: ?record type (record_reg, see enum record_type).
> + ? ? ? 8 bytes: register id (network byte order).
> + ? ? ? MAX_REGISTER_SIZE bytes: register value.
> + ? ? record_mem:
> + ? ? ? 1 byte: ?record type (record_mem, see enum record_type).
> + ? ? ? 8 bytes: memory length (network byte order).
> + ? ? ? 8 bytes: memory address (network byte order).
> + ? ? ? n bytes: memory value (n == memory length).
> +
> + ? Version 2
> + ? ? 4 bytes: magic number netorder32(0x20091016).
> + ? ? ? NOTE: be sure to change whenever this file format changes!
> +
> + ? Records:
> + ? ? record_end:
> + ? ? ? 1 byte: ?record type (record_end, see enum record_type).
> + ? ? ? 4 bytes: signal
> + ? ? ? 4 bytes: instruction count
> + ? ? record_reg:
> + ? ? ? 1 byte: ?record type (record_reg, see enum record_type).
> + ? ? ? 4 bytes: register id (network byte order).
> + ? ? ? n bytes: register value (n == actual register size).
> + ? ? ? ? ? ? ? ?(eg. 4 bytes for x86 general registers).
> + ? ? record_mem:
> + ? ? ? 1 byte: ?record type (record_mem, see enum record_type).
> + ? ? ? 4 bytes: memory length (network byte order).
> + ? ? ? 8 bytes: memory address (network byte order).
> + ? ? ? n bytes: memory value (n == memory length).
> +
> +*/
> +
> +/* bfdcore_write -- write bytes into a core file section. ?*/
> +
> +static void
> +bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset)
> +{
> + ?int ret = bfd_set_section_contents (obfd, osec, buf, *offset, len);
> +
> + ?if (ret)
> + ? ?*offset += len;
> + ?else
> + ? ?error (_("Failed to write %d bytes to core file %s ('%s').\n"),
> + ? ? ? ? ?len, bfd_get_filename (obfd),
> + ? ? ? ? ?bfd_errmsg (bfd_get_error ()));
> +}
> +
> +/* Restore the execution log from a file. ?We use a modified elf
> + ? corefile format, with an extra section for our data. ?*/
> +
> +static void
> +cmd_record_restore (char *args, int from_tty)
> +{
> + ?core_file_command (args, from_tty);
> + ?record_open (args, from_tty);
> +}
> +
> +static void
> +record_save_cleanups (void *data)
> +{
> + ?bfd *obfd = data;
> + ?char *pathname = xstrdup (bfd_get_filename (obfd));
> + ?bfd_close (obfd);
> + ?unlink (pathname);
> + ?xfree (pathname);
> +}
> +
> +/* Save the execution log to a file. ?We use a modified elf corefile
> + ? format, with an extra section for our data. ?*/
> +
> +static void
> +cmd_record_save (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;
> + ?bfd *obfd;
> + ?int save_size = 0;
> + ?asection *osec = NULL;
> + ?int bfd_offset = 0;
> +
> + ?if (strcmp (current_target.to_shortname, "record") != 0)
> + ? ?error (_("This command can only be used with target 'record'.\n"
> + ? ? ? ? ? ?"Use 'target record' first.\n"));
> +
> + ?if (args && *args)
> + ? ?recfilename = args;
> + ?else
> + ? ?{
> + ? ? ?/* Default recfile name is "gdb_record.PID". ?*/
> + ? ? ?snprintf (recfilename_buffer, sizeof (recfilename_buffer),
> + ? ? ? ? ? ? ? ?"gdb_record.%d", PIDGET (inferior_ptid));
> + ? ? ?recfilename = recfilename_buffer;
> + ? ?}
> +
> + ?/* Open the save file. ?*/
> + ?if (record_debug)
> + ? ?printf_filtered ("Saving execution log to core file '%s'\n",
> recfilename);
> +
> + ?/* Open the output file. ?*/
> + ?obfd = create_gcore_bfd (recfilename);
> + ?old_cleanups = make_cleanup (record_save_cleanups, obfd);
> +
> + ?/* 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 ();
> +
> + ?/* 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_insn (regcache, gdbarch, record_list);
> +
> + ? ? ?if (record_list->prev)
> + ? ? ? ?record_list = record_list->prev;
> + ? ?}
> +
> + ?/* Compute the size needed for the extra bfd section. ?*/
> + ?save_size = 4; ? ? ? /* magic cookie */
> + ?for (record_list = record_first.next; record_list;
> + ? ? ? record_list = record_list->next)
> + ? ?switch (record_list->type)
> + ? ? ?{
> + ? ? ?case record_end:
> + ? ? ? save_size += 1 + 4 + 4;
> + ? ? ? break;
> + ? ? ?case record_reg:
> + ? ? ? save_size += 1 + 4 + record_list->u.reg.len;
> + ? ? ? break;
> + ? ? ?case record_mem:
> + ? ? ? save_size += 1 + 4 + 8 + record_list->u.mem.len;
> + ? ? ? break;
> + ? ? ?}
> +
> + ?/* Make the new bfd section. ?*/
> + ?osec = bfd_make_section_anyway_with_flags (obfd, "precord",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SEC_HAS_CONTENTS
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | SEC_READONLY);
> + ?if (osec == NULL)
> + ? ?error (_("Failed to create 'precord' section for corefile %s: %s"),
> + ? ? ? ? ?recfilename,
> + ? ? ? ? ? bfd_errmsg (bfd_get_error ()));
> + ?bfd_set_section_size (obfd, osec, save_size);
> + ?bfd_set_section_vma (obfd, osec, 0);
> + ?bfd_set_section_alignment (obfd, osec, 0);
> + ?bfd_section_lma (obfd, osec) = 0;
> +
> + ?/* Save corefile state. ?*/
> + ?write_gcore_file (obfd);
> +
> + ?/* Write out the record log. ?*/
> + ?/* Write the magic code. ?*/
> + ?magic = RECORD_FILE_MAGIC;
> + ?if (record_debug)
> + ? ?printf_filtered ("\
> + ?Writing 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n",
> + ? ? ? ? ? ? ? ? ? ?magic);
> + ?bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset);
> +
> + ?/* Save the entries to recfd and forward execute to the end of
> + ? ? record list. ?*/
> + ?record_list = &record_first;
> + ?while (1)
> + ? ?{
> + ? ? ?/* Save entry. ?*/
> + ? ? ?if (record_list != &record_first)
> + ? ? ? ?{
> + ? ? ? ? uint8_t type;
> + ? ? ? ? uint32_t regnum, len, signal, count;
> + ? ? ? ? ?uint64_t addr;
> +
> + ? ? ? ? type = record_list->type;
> + ? ? ? ? ?bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset);
> +
> + ? ? ? ? ?switch (record_list->type)
> + ? ? ? ? ? ?{
> + ? ? ? ? ? ?case record_reg: /* reg */
> + ? ? ? ? ? ? ?if (record_debug)
> + ? ? ? ? ? ? ? printf_filtered ("\
> + ?Writing register %d (1 plus %d plus %d bytes)\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.reg.num,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (regnum),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.reg.len);
> +
> + ? ? ? ? ? ? ?/* Write regnum. ?*/
> + ? ? ? ? ? ? ?regnum = netorder32 (record_list->u.reg.num);
> + ? ? ? ? ? ? ?bfdcore_write (obfd, osec, &regnum,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (regnum), &bfd_offset);
> +
> + ? ? ? ? ? ? ?/* Write regval. ?*/
> + ? ? ? ? ? ? ?bfdcore_write (obfd, osec, record_get_loc (record_list),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.reg.len, &bfd_offset);
> + ? ? ? ? ? ? ?break;
> +
> + ? ? ? ? ? ?case record_mem: /* mem */
> + ? ? ? ? ? ? if (record_debug)
> + ? ? ? ? ? ? ? printf_filtered ("\
> + ?Writing memory %s (1 plus %d plus %d plus %d bytes)\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?paddress (gdbarch,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.addr),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (addr),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (len),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.len);
> +
> + ? ? ? ? ? ? /* Write memlen. ?*/
> + ? ? ? ? ? ? len = netorder32 (record_list->u.mem.len);
> + ? ? ? ? ? ? bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset);
> +
> + ? ? ? ? ? ? /* Write memaddr. ?*/
> + ? ? ? ? ? ? addr = netorder64 (record_list->u.mem.addr);
> + ? ? ? ? ? ? bfdcore_write (obfd, osec, &addr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (addr), &bfd_offset);
> +
> + ? ? ? ? ? ? /* Write memval. ?*/
> + ? ? ? ? ? ? bfdcore_write (obfd, osec, record_get_loc (record_list),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.len, &bfd_offset);
> + ? ? ? ? ? ? ?break;
> +
> + ? ? ? ? ? ? ?case record_end:
> + ? ? ? ? ? ? ? ?if (record_debug)
> + ? ? ? ? ? ? ? ? ?printf_filtered ("\
> + ?Writing record_end (1 + %d + %d bytes)\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (signal),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (count));
> + ? ? ? ? ? ? ? /* Write signal value. ?*/
> + ? ? ? ? ? ? ? signal = netorder32 (record_list->u.end.sigval);
> + ? ? ? ? ? ? ? bfdcore_write (obfd, osec, &signal,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (signal), &bfd_offset);
> +
> + ? ? ? ? ? ? ? /* Write insn count. ?*/
> + ? ? ? ? ? ? ? count = netorder32 (record_list->u.end.insn_num);
> + ? ? ? ? ? ? ? bfdcore_write (obfd, osec, &count,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (count), &bfd_offset);
> + ? ? ? ? ? ? ? ?break;
> + ? ? ? ? ? ?}
> + ? ? ? ?}
> +
> + ? ? ?/* Execute entry. ?*/
> + ? ? ?record_exec_insn (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_insn (regcache, gdbarch, record_list);
> +
> + ? ? ?if (record_list->prev)
> + ? ? ? ?record_list = record_list->prev;
> + ? ?}
> +
> + ?do_cleanups (set_cleanups);
> + ?do_cleanups (old_cleanups);
> +
> + ?/* Succeeded. ?*/
> + ?printf_filtered (_("Saved core file %s with execution log.\n"),
> + ? ? ? ? ? ? ? ? ?recfilename);
> +}
> +
> ?/* Truncate the record log from the present point
> ? ?of replay until the end. ?*/
>
> @@ -1749,6 +2252,8 @@ info_record_command (char *args, int fro
> ?void
> ?_initialize_record (void)
> ?{
> + ?struct cmd_list_element *c;
> +
> ? /* Init record_first. ?*/
> ? record_first.prev = NULL;
> ? record_first.next = NULL;
> @@ -1767,10 +2272,12 @@ _initialize_record (void)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ?NULL, show_record_debug, &setdebuglist,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ?&showdebuglist);
>
> - ?add_prefix_cmd ("record", class_obscure, cmd_record_start,
> + ?c = add_prefix_cmd ("record", class_obscure, cmd_record_start,
> ? ? ? ? ? ? ? ? ?_("Abbreviated form of \"target record\" command."),
> ? ? ? ? ? ? ? ? ?&record_cmdlist, "record ", 0, &cmdlist);
> + ?set_cmd_completer (c, filename_completer);
> ? add_com_alias ("rec", "record", class_obscure, 1);
> +
> ? add_prefix_cmd ("record", class_support, set_record_command,
> ? ? ? ? ? ? ? ? ?_("Set record options"), &set_record_cmdlist,
> ? ? ? ? ? ? ? ? ?"set record ", 0, &setlist);
> @@ -1784,6 +2291,17 @@ _initialize_record (void)
> ? ? ? ? ? ? ? ? ?"info record ", 0, &infolist);
> ? add_alias_cmd ("rec", "record", class_obscure, 1, &infolist);
>
> + ?c = add_cmd ("save", class_obscure, cmd_record_save,
> + ? ? ? ? ? ? ?_("Save the execution log to a file.\n\
> +Argument is optional filename.\n\
> +Default filename is 'gdb_record.<process_id>'."),
> + ? ? ? ? ? ? ?&record_cmdlist);
> +
> + ?c = add_cmd ("restore", class_obscure, cmd_record_restore,
> + ? ? ? ? ? ? ?_("Restore the execution log from a file.\n\
> +Argument is filename. ?File must be created with 'record save'."),
> + ? ? ? ? ? ? ?&record_cmdlist);
> + ?set_cmd_completer (c, filename_completer);
>
> ? add_cmd ("delete", class_obscure, cmd_record_delete,
> ? ? ? ? ? _("Delete the rest of execution log and start recording it
> anew."),
>
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]