This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [RFA/RFC] Add dump and load command to process record (file format etc)
Thanks for your work, Michael.
I make it in a amd64:
gcc -g -I. -I../../src/gdb -I../../src/gdb/common
-I../../src/gdb/config -DLOCALEDIR="\"/usr/local/share/locale\""
-DHAVE_CONFIG_H -I../../src/gdb/../include/opcode
-I../../src/gdb/../readline/.. -I../bfd -I../../src/gdb/../bfd
-I../../src/gdb/../include -I../libdecnumber
-I../../src/gdb/../libdecnumber -I../../src/gdb/gnulib -Ignulib
-DMI_OUT=1 -DTUI=1 -DGDBTK -Wall -Wdeclaration-after-statement
-Wpointer-arith -Wformat-nonliteral -Wno-pointer-sign -Wno-unused
-Wno-switch -Wno-char-subscripts -Werror -c -o record.o -MT record.o
-MMD -MP -MF .deps/record.Tpo ../../src/gdb/record.c
cc1: warnings being treated as errors
../../src/gdb/record.c: In function 'cmd_record_dump':
../../src/gdb/record.c:1359: error: format '%016llx' expects type
'long long unsigned int', but argument 4 has type 'long unsigned int'
../../src/gdb/record.c: In function 'cmd_record_load':
../../src/gdb/record.c:1544: error: format '%016llx' expects type
'long long unsigned int', but argument 4 has type 'long unsigned int'
make[2]: *** [record.o] Error 1
make[2]: Leaving directory `/home/teawater/gdb/bgdbno/gdb'
make[1]: *** [all-gdb] Error 2
make[1]: Leaving directory `/home/teawater/gdb/bgdbno'
make: *** [all] Error 2
if (record_debug)
fprintf_filtered (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);
The val is not very important. Please remove it.
(top-gdb) n
29 args.argc = argc;
(top-gdb) record dump
BFD: rec.20370: warning: allocated section `precord' not in segment
Saved recfile rec.20370.
(top-gdb) quit
I got a warning.
./gdb ./gdb
GNU gdb (GDB) 6.8.50.20090815-cvs
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Setting up the environment for debugging gdb.
During symbol reading, DW_AT_name missing from DW_TAG_base_type.
During symbol reading, unsupported tag: 'DW_TAG_const_type'.
Breakpoint 1 at 0x47ab5c: file ../../src/gdb/utils.c, line 1002.
During symbol reading, DW_AT_type missing from DW_TAG_subrange_type.
Breakpoint 2 at 0x4d79c6: file ../../src/gdb/cli/cli-cmds.c, line 204.
(top-gdb) record load ./rec.20370
You can't do that without a process to debug.
(top-gdb)
I found that you try to let prec load core without corelow. And make
the record message and core message together is a very cool idea. But
I think it need change a lot of thing of prec. For example: memory,
reg, exec.
If it need let the inferior exec first, it will not work in other arch host.
The following is the my opinion.
On Thu, Aug 13, 2009 at 06:31, Michael Snyder<msnyder@vmware.com> wrote:
> Tom Tromey wrote:
>>>>>>>
>>>>>>> "Michael" == Michael Snyder <msnyder@vmware.com> writes:
>>
>> A few little nits in this patch. ?Most of these appear more than once.
>>
>> Michael> +extern bfd *
>> Michael> +create_gcore_bfd (char *filename)
>> Michael> ?{
>>
>> Don't use "extern" on definitions.
>> ?Michael> +static bfd_vma
>> Michael> +call_target_sbrk (int sbrk_arg)
>>
>> New functions should have an explanatory comment.
>>
>> Michael> +#include <fcntl.h>
>> Michael> +#ifndef O_BINARY
>> Michael> +#define O_BINARY 0
>> Michael> +#endif
>> Michael> +
>> Michael> +#include "regcache.h"
>> Michael> +#include "regset.h"
>>
>> I think adding #includes in the middle of a file is ugly.
>>
>> Also, I think the O_BINARY define isn't needed -- it looks to me that
>> defs.h does this.
>
> Tom, thanks for the review.
> Added gcore.h to export those externs, and moved one decl into inferior.h
> (always meant to do that for linux-fork).
>
>
> 2009-08-11 ?Hui Zhu ?<teawater@gmail.com>
> ? ? ? ? ? ?Michael Snyder ?<msnyder@vmware.com>
>
> ? ? ? ?* record.c (RECORD_FILE_MAGIC): New constant.
> ? ? ? ?(cmd_record_dump): New function.
> ? ? ? ?(cmd_record_load): New function.
> ? ? ? ?(bfdcore_read): New function.
> ? ? ? ?(bfdcore_write): New function.
> ? ? ? ?(record_exec_entry): New function, abstracted from record_wait.
> ? ? ? ?(record_wait): Call record_exec_entry.
> ? ? ? ?(_initialize_record): Add 'record dump' and 'record load' commands.
> ? ? ? ?(record_arch_list_add_reg): Use xcalloc instead of xmalloc.
> ? ? ? ?(record_list_release): Finish releasing record list.
>
> ? ? ? ?* gcore.c (create_gcore_bfd): New function, abstracted
> ? ? ? ?from gcore_command for export.
> ? ? ? ?(write_gcore_file): New function, abstracted from
> ? ? ? ?gcore_command for export.
> ? ? ? ?(gcore_command): Call helper functions (above).
>
> ? ? ? ?(call_target_sbrk): New function, abstracted from
> ? ? ? ?derive_heap_segment.
> ? ? ? ?(derive_heap_segment): Call helper function (above).
>
> ? ? ? ?(load_core_segments): New function.
> ? ? ? ?(load_corefile): New function.
>
> ? ? ? ?* gcore.h: New file.
> ? ? ? ?* inferior.h: Export nullify_last_target_wait_ptid from infrun.c
> ? ? ? ?for use by record.c and linux-fork.c.
> ? ? ? ?* linux-fork.c (fork_load_infrun_state): Delete extern decl.
>
> Index: gcore.h
> ===================================================================
> RCS file: gcore.h
> diff -N gcore.h
> --- /dev/null ? 1 Jan 1970 00:00:00 -0000
> +++ gcore.h ? ? 12 Aug 2009 22:28:43 -0000
> @@ -0,0 +1,23 @@
> +/* Support for reading/writing gcore files.
> +
> + ? Copyright (C) 2009, Free Software Foundation, Inc.
> +
> + ? This file is part of GDB.
> +
> + ? This program is free software; you can redistribute it and/or modify
> + ? it under the terms of the GNU General Public License as published by
> + ? the Free Software Foundation; either version 3 of the License, or
> + ? (at your option) any later version.
> +
> + ? This program is distributed in the hope that it will be useful,
> + ? but WITHOUT ANY WARRANTY; without even the implied warranty of
> + ? MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + ? GNU General Public License for more details.
> +
> + ? You should have received a copy of the GNU General Public License
> + ? along with this program. ?If not, see <http://www.gnu.org/licenses/>.
> ?*/
> +
> +extern bfd *create_gcore_bfd (char *filename);
> +extern void write_gcore_file (bfd *obfd);
> +extern bfd *load_corefile (char *filename, int from_tty);
> +
> Index: inferior.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/inferior.h,v
> retrieving revision 1.135
> diff -u -p -r1.135 inferior.h
> --- inferior.h ?28 Jun 2009 00:20:22 -0000 ? ? ?1.135
> +++ inferior.h ?12 Aug 2009 22:28:43 -0000
> @@ -236,6 +236,8 @@ extern void get_last_target_status(ptid_
>
> ?extern void follow_inferior_reset_breakpoints (void);
>
> +extern void nullify_last_target_wait_ptid (void);
> +
> ?/* Throw an error indicating the current thread is running. ?*/
> ?extern void error_is_running (void);
>
> Index: gcore.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gcore.c,v
> retrieving revision 1.34
> diff -u -p -r1.34 gcore.c
> --- gcore.c ? ? 2 Jul 2009 17:21:06 -0000 ? ? ? 1.34
> +++ gcore.c ? ? 12 Aug 2009 22:28:43 -0000
> @@ -25,10 +25,14 @@
> ?#include "gdbcore.h"
> ?#include "objfiles.h"
> ?#include "symfile.h"
> -
> +#include "arch-utils.h"
> +#include "completer.h"
> +#include "gcore.h"
> ?#include "cli/cli-decode.h"
> -
> ?#include "gdb_assert.h"
> +#include <fcntl.h>
> +#include "regcache.h"
> +#include "regset.h"
>
> ?/* The largest amount of memory to read from the target at once. ?We
> ? ?must throttle it to limit the amount of memory used by GDB during
> @@ -40,45 +44,27 @@ static enum bfd_architecture default_gco
> ?static unsigned long default_gcore_mach (void);
> ?static int gcore_memory_sections (bfd *);
>
> -/* Generate a core file from the inferior process. ?*/
> +/* create_gcore_bfd -- helper for gcore_command (exported). ?*/
>
> -static void
> -gcore_command (char *args, int from_tty)
> +bfd *
> +create_gcore_bfd (char *filename)
> ?{
> - ?struct cleanup *old_chain;
> - ?char *corefilename, corefilename_buffer[40];
> - ?asection *note_sec = NULL;
> - ?bfd *obfd;
> - ?void *note_data = NULL;
> - ?int note_size = 0;
> -
> - ?/* No use generating a corefile without a target process. ?*/
> - ?if (!target_has_execution)
> - ? ?noprocess ();
> -
> - ?if (args && *args)
> - ? ?corefilename = args;
> - ?else
> - ? ?{
> - ? ? ?/* Default corefile name is "core.PID". ?*/
> - ? ? ?sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_ptid));
> - ? ? ?corefilename = corefilename_buffer;
> - ? ?}
> -
> - ?if (info_verbose)
> - ? ?fprintf_filtered (gdb_stdout,
> - ? ? ? ? ? ? ? ? ? ? "Opening corefile '%s' for output.\n", corefilename);
> -
> - ?/* Open the output file. ?*/
> - ?obfd = bfd_openw (corefilename, default_gcore_target ());
> + ?bfd *obfd = bfd_openw (filename, default_gcore_target ());
> ? if (!obfd)
> - ? ?error (_("Failed to open '%s' for output."), corefilename);
> -
> - ?/* Need a cleanup that will close the file (FIXME: delete it?). ?*/
> - ?old_chain = make_cleanup_bfd_close (obfd);
> -
> + ? ?error (_("Failed to open '%s' for output."), filename);
> ? bfd_set_format (obfd, bfd_core);
> ? bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ());
> + ?return obfd;
> +}
> +
> +/* write_gcore_file -- helper for gcore_command (exported). ?*/
> +
> +void
> +write_gcore_file (bfd *obfd)
> +{
> + ?void *note_data = NULL;
> + ?int note_size = 0;
> + ?asection *note_sec = NULL;
>
> ? /* An external target method must build the notes section. ?*/
> ? note_data = target_make_corefile_notes (obfd, ¬e_size);
> @@ -107,9 +93,47 @@ gcore_command (char *args, int from_tty)
> ? if (note_data != NULL && note_size != 0)
> ? ? {
> ? ? ? if (!bfd_set_section_contents (obfd, note_sec, note_data, 0,
> note_size))
> - ? ? ? warning (_("writing note section (%s)"), bfd_errmsg (bfd_get_error
> ()));
> + ? ? ? warning (_("writing note section (%s)"),
> + ? ? ? ? ? ? ? ?bfd_errmsg (bfd_get_error ()));
> + ? ?}
> +}
> +
> +/* gcore_command -- implements the 'gcore' command.
> + ? Generate a core file from the inferior process. ?*/
> +
> +static void
> +gcore_command (char *args, int from_tty)
> +{
> + ?struct cleanup *old_chain;
> + ?char *corefilename, corefilename_buffer[40];
> + ?bfd *obfd;
> +
> + ?/* No use generating a corefile without a target process. ?*/
> + ?if (!target_has_execution)
> + ? ?noprocess ();
> +
> + ?if (args && *args)
> + ? ?corefilename = args;
> + ?else
> + ? ?{
> + ? ? ?/* Default corefile name is "core.PID". ?*/
> + ? ? ?sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_ptid));
> + ? ? ?corefilename = corefilename_buffer;
> ? ? }
>
> + ?if (info_verbose)
> + ? ?fprintf_filtered (gdb_stdout,
> + ? ? ? ? ? ? ? ? ? ? "Opening corefile '%s' for output.\n", corefilename);
> +
> + ?/* Open the output file. ?*/
> + ?obfd = create_gcore_bfd (corefilename);
> +
> + ?/* Need a cleanup that will close the file (FIXME: delete it?). ?*/
> + ?old_chain = make_cleanup_bfd_close (obfd);
> +
> + ?/* Call worker function. ?*/
> + ?write_gcore_file (obfd);
> +
> ? /* Succeeded. ?*/
> ? fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename);
>
> @@ -212,6 +236,50 @@ derive_stack_segment (bfd_vma *bottom, b
> ? return 1;
> ?}
>
> +/* call_target_sbrk --
> + ? helper function for derive_heap_segment and load_core_segment. ?*/
> +
> +static bfd_vma
> +call_target_sbrk (int sbrk_arg)
> +{
> + ?struct objfile *sbrk_objf;
> + ?struct gdbarch *gdbarch;
> + ?bfd_vma top_of_heap;
> + ?struct value *target_sbrk_arg;
> + ?struct value *sbrk_fn, *ret;
> + ?bfd_vma tmp;
> +
> + ?if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL)
> + ? ?{
> + ? ? ?sbrk_fn = find_function_in_inferior ("sbrk", &sbrk_objf);
> + ? ? ?if (sbrk_fn == NULL)
> + ? ? ? return (bfd_vma) 0;
> + ? ?}
> + ?else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL)
> + ? ?{
> + ? ? ?sbrk_fn = find_function_in_inferior ("_sbrk", &sbrk_objf);
> + ? ? ?if (sbrk_fn == NULL)
> + ? ? ? return (bfd_vma) 0;
> + ? ?}
> + ?else
> + ? ?return (bfd_vma) 0;
> +
> + ?gdbarch = get_objfile_arch (sbrk_objf);
> + ?target_sbrk_arg = value_from_longest (builtin_type
> (gdbarch)->builtin_int,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sbrk_arg);
> + ?gdb_assert (target_sbrk_arg);
> + ?ret = call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg);
> + ?if (ret == NULL)
> + ? ?return (bfd_vma) 0;
> +
> + ?tmp = value_as_long (ret);
> + ?if ((LONGEST) tmp <= 0 || (LONGEST) tmp == 0xffffffff)
> + ? ?return (bfd_vma) 0;
> +
> + ?top_of_heap = tmp;
> + ?return top_of_heap;
> +}
> +
> ?/* Derive a reasonable heap segment for ABFD by looking at sbrk and
> ? ?the static data sections. ?Store its limits in *BOTTOM and *TOP.
> ? ?Return non-zero if successful. ?*/
> @@ -219,12 +287,10 @@ derive_stack_segment (bfd_vma *bottom, b
> ?static int
> ?derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top)
> ?{
> - ?struct objfile *sbrk_objf;
> ? struct gdbarch *gdbarch;
> ? bfd_vma top_of_data_memory = 0;
> ? bfd_vma top_of_heap = 0;
> ? bfd_size_type sec_size;
> - ?struct value *zero, *sbrk;
> ? bfd_vma sec_vaddr;
> ? asection *sec;
>
> @@ -259,29 +325,9 @@ derive_heap_segment (bfd *abfd, bfd_vma
> ? ? ? ?}
> ? ? }
>
> - ?/* Now get the top-of-heap by calling sbrk in the inferior. ?*/
> - ?if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL)
> - ? ?{
> - ? ? ?sbrk = find_function_in_inferior ("sbrk", &sbrk_objf);
> - ? ? ?if (sbrk == NULL)
> - ? ? ? return 0;
> - ? ?}
> - ?else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL)
> - ? ?{
> - ? ? ?sbrk = find_function_in_inferior ("_sbrk", &sbrk_objf);
> - ? ? ?if (sbrk == NULL)
> - ? ? ? return 0;
> - ? ?}
> - ?else
> - ? ?return 0;
> -
> - ?gdbarch = get_objfile_arch (sbrk_objf);
> - ?zero = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
> - ?gdb_assert (zero);
> - ?sbrk = call_function_by_hand (sbrk, 1, &zero);
> - ?if (sbrk == NULL)
> + ?top_of_heap = call_target_sbrk (0);
> + ?if (top_of_heap == (bfd_vma) 0)
> ? ? return 0;
> - ?top_of_heap = value_as_long (sbrk);
>
> ? /* Return results. ?*/
> ? if (top_of_heap > top_of_data_memory)
> @@ -299,13 +345,15 @@ static void
> ?make_output_phdrs (bfd *obfd, asection *osec, void *ignored)
> ?{
> ? int p_flags = 0;
> - ?int p_type;
> + ?int p_type = 0;
>
> ? /* FIXME: these constants may only be applicable for ELF. ?*/
> ? if (strncmp (bfd_section_name (obfd, osec), "load", 4) == 0)
> ? ? p_type = PT_LOAD;
> - ?else
> + ?else if (strncmp (bfd_section_name (obfd, osec), "note", 4) == 0)
> ? ? p_type = PT_NOTE;
> + ?else
> + ? ?p_type = PT_NULL;
>
> ? p_flags |= PF_R; ? ? /* Segment is readable. ?*/
> ? if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY))
> @@ -516,6 +564,141 @@ gcore_memory_sections (bfd *obfd)
> ? return 1;
> ?}
>
> +struct load_core_args_params {
> + ?int from_tty;
> + ?bfd_vma top_of_heap;
> +};
> +
> +/* load_core_segments -- iterator function for bfd_map_over_sections. ?*/
> +
> +static void
> +load_core_segment (bfd *abfd, asection *asect, void *arg)
> +{
> + ?struct load_core_args_params *params = arg;
> + ?struct cleanup *old_chain;
> + ?char *memhunk;
> + ?int ret;
> +
> + ?if ((bfd_section_size (abfd, asect) > 0) &&
> + ? ? ?(bfd_get_section_flags (abfd, asect) & SEC_LOAD) &&
> + ? ? ?!(bfd_get_section_flags (abfd, asect) & SEC_READONLY))
> + ? ?{
> + ? ? ?if (info_verbose && params->from_tty)
> + ? ? ? {
> + ? ? ? ? printf_filtered (_("Load core section %s"),
> + ? ? ? ? ? ? ? ? ? ? ? ? ?bfd_section_name (abfd, asect));
> + ? ? ? ? printf_filtered (_(", vma 0x%08lx to 0x%08lx"),
> + ? ? ? ? ? ? ? ? ? ? ? ? ?(unsigned long) bfd_section_vma (abfd, asect),
> + ? ? ? ? ? ? ? ? ? ? ? ? ?(unsigned long) bfd_section_vma (abfd, asect) +
> + ? ? ? ? ? ? ? ? ? ? ? ? ?(int) bfd_section_size (abfd, asect));
> + ? ? ? ? printf_filtered (_(", size = %d"),
> + ? ? ? ? ? ? ? ? ? ? ? ? ?(int) bfd_section_size (abfd, asect));
> + ? ? ? ? printf_filtered (_(".\n"));
> + ? ? ? }
> + ? ? ?/* Fixme cleanup? */
> + ? ? ?memhunk = xmalloc (bfd_section_size (abfd, asect));
> + ? ? ?bfd_get_section_contents (abfd, asect, memhunk, 0,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bfd_section_size (abfd, asect));
> + ? ? ?if ((ret = target_write_memory (bfd_section_vma (abfd, asect),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? memhunk,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bfd_section_size (abfd, asect))) != 0)
> + ? ? ? {
> + ? ? ? ? print_sys_errmsg ("load_core_segment", ret);
> + ? ? ? ? if ((LONGEST) params->top_of_heap <
> + ? ? ? ? ? ? (LONGEST) bfd_section_vma (abfd, asect) +
> + ? ? ? ? ? ? (LONGEST) bfd_section_size (abfd, asect))
> + ? ? ? ? ? {
> + ? ? ? ? ? ? int increment = bfd_section_vma (abfd, asect) +
> + ? ? ? ? ? ? ? bfd_section_size (abfd, asect) - params->top_of_heap;
> +
> + ? ? ? ? ? ? params->top_of_heap = call_target_sbrk (increment);
> + ? ? ? ? ? ? if (params->top_of_heap == 0)
> + ? ? ? ? ? ? ? error ("sbrk failed, TOH = 0x%08lx", params->top_of_heap);
> + ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? printf_filtered ("Increase TOH to 0x%08lx and retry.\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(unsigned long) params->top_of_heap);
> + ? ? ? ? ? ? if (target_write_memory (bfd_section_vma (abfd, asect),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?memhunk,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?bfd_section_size (abfd, asect)) != 0)
> + ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? ? error ("Nope, still failed.");
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? }
> + ? ? ? }
> + ? ? ?xfree (memhunk);
> + ? ?}
> +}
> +
> +/* load_corefile -- reads a corefile, copies its memory sections
> + ? into target memory, and its registers into target regcache. ?*/
> +
> +bfd *
> +load_corefile (char *filename, int from_tty)
> +{
It sames that corelow.c core_open do something same with this
function, do you think we need share this function to core_open?
> + ?struct load_core_args_params params;
> + ?struct bfd_section *regsect;
> + ?const struct regset *regset;
> + ?struct regcache *regcache;
> + ?struct cleanup *old_chain;
> + ?struct gdbarch *gdbarch;
> + ?char *scratch_path;
> + ?int scratch_chan;
> + ?char *contents;
> + ?bfd *core_bfd;
> + ?int size;
> +
> + ?scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename,
> + ? ? ? ? ? ? ? ? ? ? ? O_BINARY | O_RDONLY | O_LARGEFILE, &scratch_path);
> + ?if (scratch_chan < 0)
> + ? ?perror_with_name (filename);
> +
> + ?core_bfd = bfd_fdopenr (scratch_path, gnutarget, scratch_chan);
> + ?old_chain = make_cleanup_bfd_close (core_bfd);
> + ?if (!core_bfd)
> + ? ?perror_with_name (scratch_path);
> +
> + ?if (!bfd_check_format (core_bfd, bfd_core))
> + ? ?error (_("\"%s\" is not a core file: %s"),
> + ? ? ? ? ?filename, bfd_errmsg (bfd_get_error ()));
> +
> + ?params.from_tty = from_tty;
> + ?params.top_of_heap = call_target_sbrk (0);
> + ?if (params.top_of_heap == 0)
> + ? ?error (_("Couldn't get sbrk."));
> +
> + ?bfd_map_over_sections (core_bfd, load_core_segment, (void *) ¶ms);
> + ?/* Now need to get/set registers. ?*/
> + ?regsect = bfd_get_section_by_name (core_bfd, ".reg");
> +
> + ?if (!regsect)
> + ? ?error (_("Couldn't find .reg section."));
> +
> + ?size = bfd_section_size (core_bfd, regsect);
> + ?contents = alloca (size);
> + ?bfd_get_section_contents (core_bfd, regsect, contents, 0, size);
> +
> + ?/* See FIXME kettenis/20031023 comment in corelow.c */
> + ?gdbarch = gdbarch_from_bfd (core_bfd);
> +
> + ?if (gdbarch && gdbarch_regset_from_core_section_p (gdbarch))
> + ? ?{
> + ? ? ?regset = gdbarch_regset_from_core_section (gdbarch, ".reg", size);
> + ? ? ?if (!regset)
> + ? ? ? error (_("Failed to allocate regset."));
> +
> + ? ? ?registers_changed ();
> + ? ? ?regcache = get_current_regcache ();
> + ? ? ?regset->supply_regset (regset, regcache, -1, contents, size);
> + ? ? ?reinit_frame_cache ();
> + ? ? ?target_store_registers (regcache, -1);
> + ? ?}
> + ?else
> + ? ?error (_("Failed to get regset from core section"));
> +
> + ?discard_cleanups (old_chain);
> + ?return core_bfd;
> +}
> +
> ?/* Provide a prototype to silence -Wmissing-prototypes. ?*/
> ?extern initialize_file_ftype _initialize_gcore;
>
> Index: record.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/record.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 record.c
> --- record.c ? ?8 Aug 2009 01:57:44 -0000 ? ? ? 1.11
> +++ record.c ? ?12 Aug 2009 22:28:43 -0000
> @@ -23,15 +23,24 @@
> ?#include "gdbthread.h"
> ?#include "event-top.h"
> ?#include "exceptions.h"
> +#include "completer.h"
> ?#include "record.h"
>
> +#include <byteswap.h>
> ?#include <signal.h>
> +#include <netinet/in.h>
> +#include "elf-bfd.h"
> +#include "gdbcore.h"
> +#include <ctype.h>
> +#include "gcore.h"
>
> ?#define DEFAULT_RECORD_INSN_MAX_NUM ? ?200000
>
> ?#define RECORD_IS_REPLAY \
> ? ? ?(record_list->next || execution_direction == EXEC_REVERSE)
>
> +#define RECORD_FILE_MAGIC ? ? ?htonl(0x20090726) /* Host to network order
> */
> +
> ?/* These are the core struct of record function.
>
> ? ?An record_entry is a record of the value change of a register
> @@ -146,6 +155,11 @@ record_list_release (struct record_entry
>
> ? if (rec != &record_first)
> ? ? xfree (rec);
> +
> + ?record_list = &record_first;
> + ?record_arch_list_tail = NULL;
> + ?record_arch_list_tail = NULL;
> + ?record_insn_num = 0;
> ?}
This function have other function except clear all
record_list_release. I will post how to clear all record_list in
cmd_record_load.
>
> ?static void
> @@ -241,7 +255,7 @@ record_arch_list_add_reg (struct regcach
> ? ? ? ? ? ? ? ? ? ? ? ?num);
>
> ? rec = (struct record_entry *) xmalloc (sizeof (struct record_entry));
> - ?rec->u.reg.val = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE);
> + ?rec->u.reg.val = (gdb_byte *) xcalloc (1, MAX_REGISTER_SIZE);
> ? rec->prev = NULL;
> ? rec->next = NULL;
> ? rec->type = record_reg;
> @@ -416,6 +430,95 @@ record_gdb_operation_disable_set (void)
> ? return old_cleanups;
> ?}
>
> +static inline void
> +record_exec_entry (struct regcache *regcache, struct gdbarch *gdbarch,
> + ? ? ? ? ? ? ? ? ? struct record_entry *entry)
> +{
> + ?switch (entry->type)
> + ? ?{
> + ? ?case record_reg: /* reg */
> + ? ? ?{
> + ? ? ? ?gdb_byte reg[MAX_REGISTER_SIZE];
> +
> + ? ? ? ?if (record_debug > 1)
> + ? ? ? ? ?fprintf_unfiltered (gdb_stdlog,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"Process record: record_reg %s to "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"inferior num = %d.\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?host_address_to_string (entry),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?entry->u.reg.num);
> +
> + ? ? ? ?memset (reg, 0, sizeof (reg));
> + ? ? ? ?regcache_cooked_read (regcache, entry->u.reg.num, reg);
> + ? ? ? ?regcache_cooked_write (regcache, entry->u.reg.num,
> entry->u.reg.val);
> + ? ? ? ?memcpy (entry->u.reg.val, reg, MAX_REGISTER_SIZE);
> + ? ? ?}
> + ? ? ?break;
> +
> + ? ?case record_mem: /* mem */
> + ? ? ?{
> + ? ? ? /* Nothing to do if the entry is flagged not_accessible. ?*/
> + ? ? ? ?if (!record_list->u.mem.mem_entry_not_accessible)
> + ? ? ? ? ?{
> + ? ? ? ? ? ?gdb_byte *mem = alloca (entry->u.mem.len);
> +
> + ? ? ? ? ? ?if (record_debug > 1)
> + ? ? ? ? ? ? ?fprintf_unfiltered (gdb_stdlog,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"Process record: record_mem %s to "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"inferior addr = %s len = %d.\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?host_address_to_string (entry),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?paddress (gdbarch, entry->u.mem.addr),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.len);
> +
> + ? ? ? ? ? ?if (target_read_memory (entry->u.mem.addr, mem,
> entry->u.mem.len))
> + ? ? ? ? ? ? ?{
> + ? ? ? ? ? ? ? ?if (execution_direction == EXEC_REVERSE)
> + ? ? ? ? ? ? ? ? ?{
When it works with core file, exec forware will get some error in lib,
it need change error to warning too.
> + ? ? ? ? ? ? ? ? ? /* Read failed --
> + ? ? ? ? ? ? ? ? ? ? ?flag entry as not_accessible. ?*/
> + ? ? ? ? ? ? ? ? ? ?record_list->u.mem.mem_entry_not_accessible = 1;
> + ? ? ? ? ? ? ? ? ? ?if (record_debug)
> + ? ? ? ? ? ? ? ? ? ? ?warning (_("Process record: error reading memory at "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "addr = %s len = %d."),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? paddress (gdbarch, entry->u.mem.addr),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? entry->u.mem.len);
> + ? ? ? ? ? ? ? ? ?}
> + ? ? ? ? ? ? ? ?else
> + ? ? ? ? ? ? ? ? ?error (_("Process record: error reading memory at "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? "addr = %s len = %d."),
> + ? ? ? ? ? ? ? ? ? ? ? ? paddress (gdbarch, entry->u.mem.addr),
> + ? ? ? ? ? ? ? ? ? ? ? ?entry->u.mem.len);
> + ? ? ? ? ? ? ?}
> + ? ? ? ? ? ?else
> + ? ? ? ? ? ? ?{
> + ? ? ? ? ? ? ? ?if (target_write_memory (entry->u.mem.addr,
> entry->u.mem.val,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? entry->u.mem.len))
> + ? ? ? ? ? ? ? ? ?{
> + ? ? ? ? ? ? ? ? ? ?if (execution_direction == EXEC_REVERSE)
> + ? ? ? ? ? ? ? ? ? ? ?{
> + ? ? ? ? ? ? ? ? ? ? ? /* Write failed --
> + ? ? ? ? ? ? ? ? ? ? ? ? ?flag entry as not_accessible. ?*/
> + ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.mem_entry_not_accessible = 1;
> + ? ? ? ? ? ? ? ? ? ? ? ?if (record_debug)
> + ? ? ? ? ? ? ? ? ? ? ? ? ?warning (_("Process record: error writing memory
> at "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "addr = %s len = %d."),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? paddress (gdbarch, entry->u.mem.addr),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? entry->u.mem.len);
> + ? ? ? ? ? ? ? ? ? ? ?}
> + ? ? ? ? ? ? ? ? ? ?else
> + ? ? ? ? ? ? ? ? ? ? ?error (_("Process record: error writing memory at "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "addr = %s len = %d."),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? paddress (gdbarch, entry->u.mem.addr),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?entry->u.mem.len);
> + ? ? ? ? ? ? ? ? ?}
> + ? ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? ? memcpy (entry->u.mem.val, mem, entry->u.mem.len);
> + ? ? ? ? ? ? ?}
> + ? ? ? ? ?}
> + ? ? ?}
> + ? ? ?break;
> + ? ?}
> +}
> +
> ?static void
> ?record_open (char *name, int from_tty)
> ?{
> @@ -712,76 +815,9 @@ record_wait (struct target_ops *ops,
> ? ? ? ? ? ? ?break;
> ? ? ? ? ? ?}
>
> - ? ? ? ? /* Set ptid, register and memory according to record_list. ?*/
> - ? ? ? ? if (record_list->type == record_reg)
> - ? ? ? ? ? {
> - ? ? ? ? ? ? /* reg */
> - ? ? ? ? ? ? gdb_byte reg[MAX_REGISTER_SIZE];
> - ? ? ? ? ? ? if (record_debug > 1)
> - ? ? ? ? ? ? ? fprintf_unfiltered (gdb_stdlog,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Process record: record_reg %s to "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "inferior num = %d.\n",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? host_address_to_string (record_list),
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? record_list->u.reg.num);
> - ? ? ? ? ? ? regcache_cooked_read (regcache, record_list->u.reg.num, reg);
> - ? ? ? ? ? ? regcache_cooked_write (regcache, record_list->u.reg.num,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.reg.val);
> - ? ? ? ? ? ? memcpy (record_list->u.reg.val, reg, MAX_REGISTER_SIZE);
> - ? ? ? ? ? }
> - ? ? ? ? else if (record_list->type == record_mem)
> - ? ? ? ? ? {
> - ? ? ? ? ? ? /* mem */
> - ? ? ? ? ? ? /* Nothing to do if the entry is flagged not_accessible. ?*/
> - ? ? ? ? ? ? if (!record_list->u.mem.mem_entry_not_accessible)
> - ? ? ? ? ? ? ? {
> - ? ? ? ? ? ? ? ? gdb_byte *mem = alloca (record_list->u.mem.len);
> - ? ? ? ? ? ? ? ? if (record_debug > 1)
> - ? ? ? ? ? ? ? ? ? fprintf_unfiltered (gdb_stdlog,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Process record: record_mem %s to "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "inferior addr = %s len = %d.\n",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? host_address_to_string
> (record_list),
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? paddress (gdbarch,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? record_list->u.mem.addr),
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? record_list->u.mem.len);
> -
> - ? ? ? ? ? ? ? ? if (target_read_memory (record_list->u.mem.addr, mem,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? record_list->u.mem.len))
> - ? ? ? ? ? ? ? ? ? {
> - ? ? ? ? ? ? ? ? ? ? if (execution_direction != EXEC_REVERSE)
> - ? ? ? ? ? ? ? ? ? ? ? error (_("Process record: error reading memory at "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"addr = %s len = %d."),
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?paddress (gdbarch, record_list->u.mem.addr),
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.len);
> - ? ? ? ? ? ? ? ? ? ? else
> - ? ? ? ? ? ? ? ? ? ? ? /* Read failed --
> - ? ? ? ? ? ? ? ? ? ? ? ? ?flag entry as not_accessible. ?*/
> - ? ? ? ? ? ? ? ? ? ? ? record_list->u.mem.mem_entry_not_accessible = 1;
> - ? ? ? ? ? ? ? ? ? }
> - ? ? ? ? ? ? ? ? else
> - ? ? ? ? ? ? ? ? ? {
> - ? ? ? ? ? ? ? ? ? ? if (target_write_memory (record_list->u.mem.addr,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.val,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.len))
> - ? ? ? ? ? ? ? ? ? ? ? {
> - ? ? ? ? ? ? ? ? ? ? ? ? if (execution_direction != EXEC_REVERSE)
> - ? ? ? ? ? ? ? ? ? ? ? ? ? error (_("Process record: error writing memory
> at "
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"addr = %s len = %d."),
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?paddress (gdbarch,
> record_list->u.mem.addr),
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?record_list->u.mem.len);
> - ? ? ? ? ? ? ? ? ? ? ? ? else
> - ? ? ? ? ? ? ? ? ? ? ? ? ? /* Write failed --
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?flag entry as not_accessible. ?*/
> - ? ? ? ? ? ? ? ? ? ? ? ? ? record_list->u.mem.mem_entry_not_accessible = 1;
> - ? ? ? ? ? ? ? ? ? ? ? }
> - ? ? ? ? ? ? ? ? ? ? else
> - ? ? ? ? ? ? ? ? ? ? ? {
> - ? ? ? ? ? ? ? ? ? ? ? ? memcpy (record_list->u.mem.val, mem,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? record_list->u.mem.len);
> - ? ? ? ? ? ? ? ? ? ? ? }
> - ? ? ? ? ? ? ? ? ? }
> - ? ? ? ? ? ? ? }
> - ? ? ? ? ? }
> - ? ? ? ? else
> + ? ? ? ? ?record_exec_entry (regcache, gdbarch, record_list);
> +
> + ? ? ? ? if (record_list->type == record_end)
> ? ? ? ? ? ?{
> ? ? ? ? ? ? ?if (record_debug > 1)
> ? ? ? ? ? ? ? ?fprintf_unfiltered (gdb_stdlog,
> @@ -999,6 +1035,7 @@ record_store_registers (struct target_op
>
> ? ? ? record_registers_change (regcache, regno);
> ? ? }
> +
> ? record_beneath_to_store_registers (record_beneath_to_store_registers_ops,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?regcache, regno);
> ?}
> @@ -1153,6 +1190,448 @@ cmd_record_start (char *args, int from_t
> ? execute_command ("target record", from_tty);
> ?}
>
> +/* 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 (network byte order)
> + ? ? ?16 bytes: register value (target byte order)
> + ? ? ?record_mem:
> + ? ? ? 1 byte: ?record type (record_mem)
> + ? ? ? 8 bytes: memory address (network byte order)
> + ? ? ? 8 bytes: memory length (network byte order)
> + ? ? ? n bytes: memory value (n == memory length, target byte order)
> +
> + ? Version 2 (proposed)
> +
> + ? ? Header:
> + ? ? ? 4 bytes: magic number RECORD_FILE_MAGIC.
> + ? ? ? ? ? ? ? ?NOTE: be sure to change whenever this file format changes!
> + ? ? ? n bytes: architecture...
> + ? ? ? 4 bytes: size of register snapshot
> + ? ? ? n bytes: register snapshot
> + ? ? ? 4 bytes: number of section crcs
> + ? ? ? n bytes: section names with crcs
> +
> + ? ? Records:
> + ? ? ? See version 1.
> + */
> +
> +/* bfdcore_write -- write bytes into a core file section. ?*/
> +
> +static int
> +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;
> + ?return ret;
> +}
> +
> +/* 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;
> + ?bfd *obfd;
> + ?int dump_size = 0;
> + ?asection *osec = NULL;
> + ?struct record_entry *p;
> + ?int bfd_offset = 0;
> +
> +
> + ?if (current_target.to_stratum != record_stratum)
> + ? ?error (_("Process record is not started.\n"));
> +
> + ?if (args && *args)
> + ? ?recfilename = args;
> + ?else
> + ? ?{
> + ? ? ?/* Default recfile name is "rec.PID". ?*/
> + ? ? ?sprintf (recfilename_buffer, "rec.%d", PIDGET (inferior_ptid));
> + ? ? ?recfilename = recfilename_buffer;
> + ? ?}
> +
> + ?/* Open the dump file. ?*/
> + ?if (record_debug)
> + ? ?fprintf_filtered (gdb_stdlog,
> + ? ? ? ? ? ? ? ? ? ? _("Saving recording to file '%s'\n"),
> + ? ? ? ? ? ? ? ? ? ? recfilename);
> +
> + ?/* Open the output file. ?*/
> + ?obfd = create_gcore_bfd (recfilename);
> +
> + ?/* Need a cleanup that will close the file (FIXME: delete it?). ?*/
> + ?old_cleanups = make_cleanup_bfd_close (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. ?*/
> + ?for (; record_list && record_list != &record_first;
> + ? ? ? record_list = record_list->prev)
> + ? ?record_exec_entry (regcache, gdbarch, record_list);
> +
> + ?/* Compute the size needed for the extra bfd section. ?*/
> + ?dump_size = 4; ? ? ? /* magic cookie */
> + ?for (p = &record_first; p; p = p->next)
> + ? ?switch (p->type)
> + ? ? ?{
> + ? ? ?case record_end:
> + ? ? ? dump_size += 1;
> + ? ? ? break;
> + ? ? ?case record_reg:
> + ? ? ? dump_size += 1 + 8 + MAX_REGISTER_SIZE;
> + ? ? ? break;
> + ? ? ?case record_mem:
> + ? ? ? dump_size += 1 + 8 + 8 + p->u.mem.len;
> + ? ? ? break;
> + ? ? ?}
> +
> + ?/* Make the new bfd section. ?*/
> + ?osec = bfd_make_section_anyway (obfd, "precord");
> + ?bfd_set_section_size (obfd, osec, dump_size);
> + ?bfd_set_section_vma (obfd, osec, 0);
> + ?bfd_section_lma (obfd, osec) = 0;
> + ?bfd_set_section_flags (obfd, osec, SEC_ALLOC | SEC_HAS_CONTENTS);
> +
> + ?/* Save corefile state. ?*/
> + ?write_gcore_file (obfd);
I am not sure it is a better idea that reverse and gcore.
> +
> + ?/* Write out the record log (modified Hui method). ?*/
> + ?/* Write the magic code. ?*/
> + ?magic = RECORD_FILE_MAGIC;
> + ?if (record_debug)
> + ? ?fprintf_filtered (gdb_stdlog, _("\
> + ?Writing 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n"),
> + ? ? ? ? ? ? ? ? ? ? magic);
> + ?if (!bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset))
> + ? ?error (_("Failed to write 'magic' to %s (%s)"),
> + ? ? ? ? ?recfilename, bfd_errmsg (bfd_get_error ()));
> +
> + ?/* Dump the entries into the new bfd section. ?*/
> + ?for (p = &record_first; p; p = p->next)
> + ? ?{
> + ? ? ?uint8_t tmpu8;
> + ? ? ?uint64_t tmpu64;
> +
> + ? ? ?tmpu8 = p->type;
> + ? ? ?if (!bfdcore_write (obfd, osec, &tmpu8, sizeof (tmpu8), &bfd_offset))
> + ? ? ? error (_("Failed to write 'type' to %s (%s)"),
> + ? ? ? ? ? ? ?recfilename, bfd_errmsg (bfd_get_error ()));
> +
> + ? ? ?switch (p->type)
> + ? ? ? {
> + ? ? ? case record_reg: /* reg */
> + ? ? ? ? tmpu64 = p->u.reg.num;
> + ? ? ? ? if (BYTE_ORDER == LITTLE_ENDIAN)
> + ? ? ? ? ? tmpu64 = bswap_64 (tmpu64);
> +
> + ? ? ? ? if (record_debug)
> + ? ? ? ? ? fprintf_filtered (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);
> + ? ? ? ? /* FIXME: register num does not need 8 bytes. ?*/
> + ? ? ? ? if (!bfdcore_write (obfd, osec, &tmpu64,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof (tmpu64), &bfd_offset))
> + ? ? ? ? ? error (_("Failed to write regnum to %s (%s)"),
> + ? ? ? ? ? ? ? ? ?recfilename, bfd_errmsg (bfd_get_error ()));
> +
> + ? ? ? ? /* FIXME: add a len field, and write the smaller value. ?*/
> + ? ? ? ? if (!bfdcore_write (obfd, osec, p->u.reg.val,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MAX_REGISTER_SIZE, &bfd_offset))
> + ? ? ? ? ? error (_("Failed to write regval to %s (%s)"),
> + ? ? ? ? ? ? ? ? ?recfilename, bfd_errmsg (bfd_get_error ()));
> + ? ? ? ? break;
> + ? ? ? case record_mem: /* mem */
> + ? ? ? ? tmpu64 = p->u.mem.addr;
> + ? ? ? ? if (BYTE_ORDER == LITTLE_ENDIAN)
> + ? ? ? ? ? tmpu64 = bswap_64 (tmpu64);
> +
> + ? ? ? ? if (record_debug)
> + ? ? ? ? ? fprintf_filtered (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);
> + ? ? ? ? if (!bfdcore_write (obfd, osec, &tmpu64, sizeof (tmpu64),
> &bfd_offset))
> + ? ? ? ? ? error (_("Failed to write memaddr to %s (%s)"),
> + ? ? ? ? ? ? ? ? ?recfilename, bfd_errmsg (bfd_get_error ()));
> +
> + ? ? ? ? tmpu64 = p->u.mem.len;
> + ? ? ? ? if (BYTE_ORDER == LITTLE_ENDIAN)
> + ? ? ? ? ? tmpu64 = bswap_64 (tmpu64);
> +
> + ? ? ? ? /* FIXME: len does not need 8 bytes. ?*/
> + ? ? ? ? if (!bfdcore_write (obfd, osec, &tmpu64, sizeof (tmpu64),
> &bfd_offset))
> + ? ? ? ? ? error (_("Failed to write memlen to %s (%s)"),
> + ? ? ? ? ? ? ? ? ?recfilename, bfd_errmsg (bfd_get_error ()));
> +
> + ? ? ? ? if (!bfdcore_write (obfd, osec, p->u.mem.val,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? p->u.mem.len, &bfd_offset))
> + ? ? ? ? ? error (_("Failed to write memval to %s (%s)"),
> + ? ? ? ? ? ? ? ? ?recfilename, bfd_errmsg (bfd_get_error ()));
> + ? ? ? ? break;
> + ? ? ? case record_end:
> + ? ? ? ? /* FIXME: record the contents of record_end rec. ?*/
> + ? ? ? ? if (record_debug)
> + ? ? ? ? ? fprintf_filtered (gdb_stdlog, _("\
> + ?Writing record_end (1 byte)\n"));
> + ? ? ? ? break;
> + ? ? ? }
> + ? ?}
> +
> + ?/* Now forward-execute back to the saved entry. ?*/
> + ?for (record_list = &record_first;
> + ? ? ? record_list && record_list != cur_record_list;
> + ? ? ? record_list = record_list->next)
> + ? ?record_exec_entry (regcache, gdbarch, record_list);
> +
> + ?/* Clean-ups will close the output file and free malloc memory. ?*/
> + ?do_cleanups (old_cleanups);
> +
> + ?/* Succeeded. ?*/
> + ?fprintf_filtered (gdb_stdout, "Saved recfile %s.\n", recfilename);
> +}
> +
> +/* bfdcore_read -- read bytes from a core file section. ?*/
> +
> +static int
> +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;
> + ?return ret;
> +}
> +
> +/* 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;
> + ?bfd *core_bfd;
> + ?asection *osec;
> +
> + ?if (!args || (args && !*args))
> + ? ?error (_("Argument for filename required.\n"));
> +
> + ?/* Open the load file. ?*/
> + ?if (record_debug)
> + ? ?fprintf_filtered (gdb_stdlog,
> + ? ? ? ? ? ? ? ? ? ? _("Restoring recording from file '%s'\n"), args);
> +
> + ?/* Restore corefile regs and mem sections. ?*/
> + ?core_bfd = load_corefile (args, from_tty);
> + ?old_cleanups = make_cleanup_bfd_close (core_bfd);
> +
> + ?/* Now need to find our special note section. ?*/
> + ?osec = bfd_get_section_by_name (core_bfd, "null0");
> + ?printf_filtered ("Find precord section %s.\n",
> + ? ? ? ? ? ? ? ? ?osec ? "succeeded" : "failed");
> +
> + ?if (osec)
> + ? ?{
> + ? ? ?int i, len;
> + ? ? ?int bfd_offset = 0;
> +
> + ? ? ?if (record_debug)
> + ? ? ? fprintf_filtered (gdb_stdlog, "osec name = '%s'\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? bfd_section_name (core_bfd, osec));
> + ? ? ?len = (int) bfd_section_size (core_bfd, osec);
> + ? ? ?printf_filtered ("osec size = %d\n", len);
> +
> + ? ? ?/* Check the magic code. ?*/
> + ? ? ?if (!bfdcore_read (core_bfd, osec, &magic,
> + ? ? ? ? ? ? ? ? ? ? ? ?sizeof (magic), &bfd_offset))
> + ? ? ? error (_("Failed to read 'magic' from %s (%s)"),
> + ? ? ? ? ? ? ?args, bfd_errmsg (bfd_get_error ()));
> +
> + ? ? ?if (magic != RECORD_FILE_MAGIC)
> + ? ? ? error (_("'%s', version mis-match / file format error."),
> + ? ? ? ? ? ? ?args);
> +
> + ? ? ?if (record_debug)
> + ? ? ? fprintf_filtered (gdb_stdlog, _("\
> + ?Reading 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n"),
> + ? ? ? ? ? ? ? ? ? ? ? ? magic);
> + ? ? ?if (current_target.to_stratum != record_stratum)
> + ? ? ? {
> + ? ? ? ? /* FIXME need cleanup! ?We might error out. ?*/
> + ? ? ? ? cmd_record_start (NULL, from_tty);
> + ? ? ? ? printf_unfiltered (_("Auto start process record.\n"));
> + ? ? ? }
> +
> + ? ? ?/* Free any existing record log, and load the entries in
> + ? ? ? ?core_bfd to the new record log. ?*/
> + ? ? ?record_list_release (record_arch_list_tail);
I think this is not the right way.
First, you need check if it's empty or not.
if (record_first.next)
{
//after it, use record_exec_entry to the first entry.
/* Reverse execute to the begin of record list. */
for (; record_list && record_list != &record_first;
record_list = record_list->prev)
record_exec_entry (regcache, gdbarch, record_list);
//release all entry
record_list_release_next ();
}
> + ? ? ?old_cleanups2 = make_cleanup (record_message_cleanups, 0);
> +
> + ? ? ?while (1)
> + ? ? ? {
> + ? ? ? ? uint8_t tmpu8;
> + ? ? ? ? uint64_t tmpu64;
> +
> + ? ? ? ? /* FIXME: Check offset for end-of-section. ?*/
> + ? ? ? ? if (!bfdcore_read (core_bfd, osec, &tmpu8,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (tmpu8), &bfd_offset))
> + ? ? ? ? ? break;
> +
> + ? ? ? ? switch (tmpu8)
> + ? ? ? ? ? {
> + ? ? ? ? ? case record_reg: /* reg */
> + ? ? ? ? ? ? /* FIXME: abstract out into an 'insert' function. ?*/
> + ? ? ? ? ? ? rec = (struct record_entry *)
> + ? ? ? ? ? ? ? xmalloc (sizeof (struct record_entry));
> + ? ? ? ? ? ? rec->u.reg.val = (gdb_byte *) xcalloc (1, MAX_REGISTER_SIZE);
> + ? ? ? ? ? ? rec->prev = NULL;
> + ? ? ? ? ? ? rec->next = NULL;
> + ? ? ? ? ? ? rec->type = record_reg;
> + ? ? ? ? ? ? /* Get num. ?*/
> + ? ? ? ? ? ? /* FIXME: register num does not need 8 bytes. ?*/
> + ? ? ? ? ? ? if (!bfdcore_read (core_bfd, osec, &tmpu64,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (tmpu64), &bfd_offset))
> + ? ? ? ? ? ? ? error (_("Failed to read regnum from %s (%s)"),
> + ? ? ? ? ? ? ? ? ? ? ?args, bfd_errmsg (bfd_get_error ()));
> +
> + ? ? ? ? ? ? if (BYTE_ORDER == LITTLE_ENDIAN)
> + ? ? ? ? ? ? ? tmpu64 = bswap_64 (tmpu64);
> + ? ? ? ? ? ? rec->u.reg.num = tmpu64;
> +
> + ? ? ? ? ? ? /* Get val. ?*/
> + ? ? ? ? ? ? if (!bfdcore_read (core_bfd, osec, rec->u.reg.val,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?MAX_REGISTER_SIZE, &bfd_offset))
> + ? ? ? ? ? ? ? error (_("Failed to read regval from ?%s (%s)"),
> + ? ? ? ? ? ? ? ? ? ? ?args, bfd_errmsg (bfd_get_error ()));
> +
> + ? ? ? ? ? ? if (record_debug)
> + ? ? ? ? ? ? ? fprintf_filtered (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. ?*/
> + ? ? ? ? ? ? if (!bfdcore_read (core_bfd, osec, &tmpu64,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (tmpu64), &bfd_offset))
> + ? ? ? ? ? ? ? error (_("Failed to read memaddr from %s (%s)"),
> + ? ? ? ? ? ? ? ? ? ? ?args, bfd_errmsg (bfd_get_error ()));
> + ? ? ? ? ? ? if (BYTE_ORDER == LITTLE_ENDIAN)
> + ? ? ? ? ? ? ? tmpu64 = bswap_64 (tmpu64);
> + ? ? ? ? ? ? rec->u.mem.addr = tmpu64;
> +
> + ? ? ? ? ? ? /* Get len. ?*/
> + ? ? ? ? ? ? /* FIXME: len does not need 8 bytes. ?*/
> + ? ? ? ? ? ? if (!bfdcore_read (core_bfd, osec, &tmpu64,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof (tmpu64), &bfd_offset))
> + ? ? ? ? ? ? ? error (_("Failed to read memlen from %s (%s)"),
> + ? ? ? ? ? ? ? ? ? ? ?args, bfd_errmsg (bfd_get_error ()));
> + ? ? ? ? ? ? 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. ?*/
> + ? ? ? ? ? ? if (!bfdcore_read (core_bfd, osec, rec->u.mem.val,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?rec->u.mem.len, &bfd_offset))
> + ? ? ? ? ? ? ? error (_("Failed to read memval from %s (%s)"),
> + ? ? ? ? ? ? ? ? ? ? ?args, bfd_errmsg (bfd_get_error ()));
> + ? ? ? ? ? ? if (record_debug)
> + ? ? ? ? ? ? ? fprintf_filtered (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 */
> + ? ? ? ? ? ? /* FIXME: restore the contents of record_end rec. ?*/
> + ? ? ? ? ? ? rec = (struct record_entry *)
> + ? ? ? ? ? ? ? xmalloc (sizeof (struct record_entry));
> + ? ? ? ? ? ? rec->prev = NULL;
> + ? ? ? ? ? ? rec->next = NULL;
> + ? ? ? ? ? ? rec->type = record_end;
> + ? ? ? ? ? ? if (record_debug)
> + ? ? ? ? ? ? ? fprintf_filtered (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. ?(??? FIXME)*/
> + ?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);
> + ?registers_changed ();
> + ?reinit_frame_cache ();
> + ?nullify_last_target_wait_ptid ();
> + ?print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
> +}
> +
> ?/* Truncate the record log from the present point
> ? ?of replay until the end. ?*/
>
> @@ -1243,6 +1722,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;
> @@ -1276,6 +1757,15 @@ _initialize_record (void)
> ? ? ? ? ? ? ? ? ?"info record ", 0, &infolist);
> ? add_alias_cmd ("rec", "record", class_obscure, 1, &infolist);
>
> + ?c = add_cmd ("dump", class_obscure, cmd_record_dump,
> + ? ? ? ? ? ? ?_("Dump the execution log to a file.\n\
> +Argument is optional filename. ?Default filename is 'rec.<process_id>'."),
> + ? ? ? ? ? ? ? &record_cmdlist);
> + ?set_cmd_completer (c, filename_completer);
> + ?c = add_cmd ("load", class_obscure, cmd_record_load,
> + ? ? ? ? ? ? ?_("Load the execution log from a file. ?Argument is
> filename."),
> + ? ? ? ? ? ? ? &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."),
> @@ -1290,15 +1780,15 @@ _initialize_record (void)
>
> ? /* Record instructions number limit command. ?*/
> ? add_setshow_boolean_cmd ("stop-at-limit", no_class,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? &record_stop_at_limit, _("\
> + ? ? ? ? ? ? ? ? ? ? ? ? ?&record_stop_at_limit, _("\
> ?Set whether record/replay stops when record/replay buffer becomes full."),
> _("\
> ?Show whether record/replay stops when record/replay buffer becomes full."),
> _("\
> ?Default is ON.\n\
> ?When ON, if the record/replay buffer becomes full, ask user what to do.\n\
> ?When OFF, if the record/replay buffer becomes full,\n\
> ?delete the oldest recorded instruction to make room for each new one."),
> - ? ? ? ? ? ? ? ? ? ? ? ? ? NULL, NULL,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ?&set_record_cmdlist, &show_record_cmdlist);
> + ? ? ? ? ? ? ? ? ? ? ? ? ?NULL, NULL,
> + ? ? ? ? ? ? ? ? ? ? ? ? ?&set_record_cmdlist, &show_record_cmdlist);
> ? add_setshow_zinteger_cmd ("insn-number-max", no_class,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ?&record_insn_max_num,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ?_("Set record/replay buffer limit."),
> Index: linux-fork.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/linux-fork.c,v
> retrieving revision 1.29
> diff -u -p -r1.29 linux-fork.c
> --- linux-fork.c ? ? ? ?2 Jul 2009 22:24:07 -0000 ? ? ? 1.29
> +++ linux-fork.c ? ? ? ?12 Aug 2009 22:28:43 -0000
> @@ -235,7 +235,6 @@ call_lseek (int fd, off_t offset, int wh
> ?static void
> ?fork_load_infrun_state (struct fork_info *fp)
> ?{
> - ?extern void nullify_last_target_wait_ptid ();
> ? int i;
>
> ? linux_nat_switch_fork (fp->ptid);
>
>