From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1563 invoked by alias); 15 Aug 2009 12:22:34 -0000 Received: (qmail 1041 invoked by uid 22791); 15 Aug 2009 12:22:28 -0000 X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_44,SARE_MSGID_LONG40,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail-px0-f193.google.com (HELO mail-px0-f193.google.com) (209.85.216.193) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 15 Aug 2009 12:22:18 +0000 Received: by pxi31 with SMTP id 31so717539pxi.24 for ; Sat, 15 Aug 2009 05:22:16 -0700 (PDT) MIME-Version: 1.0 Received: by 10.143.20.40 with SMTP id x40mr504795wfi.226.1250338936084; Sat, 15 Aug 2009 05:22:16 -0700 (PDT) In-Reply-To: <4A8342AC.6070507@vmware.com> References: <83my6fo2pa.fsf@gnu.org> <4A78935B.5030508@vmware.com> <4A79E90E.6090801@vmware.com> <4A82119A.3010405@vmware.com> <4A8342AC.6070507@vmware.com> From: Hui Zhu Date: Sun, 16 Aug 2009 00:04:00 -0000 Message-ID: Subject: Re: [RFA/RFC] Add dump and load command to process record (file format etc) To: Michael Snyder Cc: "tromey@redhat.com" , "gdb-patches@sourceware.org" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-08/txt/msg00215.txt.bz2 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=3D"\"/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=3D1 -DTUI=3D1 -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 =3D 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 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: ... 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 wrote: > Tom Tromey wrote: >>>>>>> >>>>>>> "Michael" =3D=3D Michael Snyder writes: >> >> A few little nits in this patch. =A0Most of these appear more than once. >> >> Michael> +extern bfd * >> Michael> +create_gcore_bfd (char *filename) >> Michael> =A0{ >> >> Don't use "extern" on definitions. >> =A0Michael> +static bfd_vma >> Michael> +call_target_sbrk (int sbrk_arg) >> >> New functions should have an explanatory comment. >> >> Michael> +#include >> 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 =A0Hui Zhu =A0 > =A0 =A0 =A0 =A0 =A0 =A0Michael Snyder =A0 > > =A0 =A0 =A0 =A0* record.c (RECORD_FILE_MAGIC): New constant. > =A0 =A0 =A0 =A0(cmd_record_dump): New function. > =A0 =A0 =A0 =A0(cmd_record_load): New function. > =A0 =A0 =A0 =A0(bfdcore_read): New function. > =A0 =A0 =A0 =A0(bfdcore_write): New function. > =A0 =A0 =A0 =A0(record_exec_entry): New function, abstracted from record_= wait. > =A0 =A0 =A0 =A0(record_wait): Call record_exec_entry. > =A0 =A0 =A0 =A0(_initialize_record): Add 'record dump' and 'record load' = commands. > =A0 =A0 =A0 =A0(record_arch_list_add_reg): Use xcalloc instead of xmalloc. > =A0 =A0 =A0 =A0(record_list_release): Finish releasing record list. > > =A0 =A0 =A0 =A0* gcore.c (create_gcore_bfd): New function, abstracted > =A0 =A0 =A0 =A0from gcore_command for export. > =A0 =A0 =A0 =A0(write_gcore_file): New function, abstracted from > =A0 =A0 =A0 =A0gcore_command for export. > =A0 =A0 =A0 =A0(gcore_command): Call helper functions (above). > > =A0 =A0 =A0 =A0(call_target_sbrk): New function, abstracted from > =A0 =A0 =A0 =A0derive_heap_segment. > =A0 =A0 =A0 =A0(derive_heap_segment): Call helper function (above). > > =A0 =A0 =A0 =A0(load_core_segments): New function. > =A0 =A0 =A0 =A0(load_corefile): New function. > > =A0 =A0 =A0 =A0* gcore.h: New file. > =A0 =A0 =A0 =A0* inferior.h: Export nullify_last_target_wait_ptid from in= frun.c > =A0 =A0 =A0 =A0for use by record.c and linux-fork.c. > =A0 =A0 =A0 =A0* linux-fork.c (fork_load_infrun_state): Delete extern dec= l. > > Index: gcore.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > RCS file: gcore.h > diff -N gcore.h > --- /dev/null =A0 1 Jan 1970 00:00:00 -0000 > +++ gcore.h =A0 =A0 12 Aug 2009 22:28:43 -0000 > @@ -0,0 +1,23 @@ > +/* Support for reading/writing gcore files. > + > + =A0 Copyright (C) 2009, Free Software Foundation, Inc. > + > + =A0 This file is part of GDB. > + > + =A0 This program is free software; you can redistribute it and/or modify > + =A0 it under the terms of the GNU General Public License as published by > + =A0 the Free Software Foundation; either version 3 of the License, or > + =A0 (at your option) any later version. > + > + =A0 This program is distributed in the hope that it will be useful, > + =A0 but WITHOUT ANY WARRANTY; without even the implied warranty of > + =A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the > + =A0 GNU General Public License for more details. > + > + =A0 You should have received a copy of the GNU General Public License > + =A0 along with this program. =A0If not, see . > =A0*/ > + > +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 > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > RCS file: /cvs/src/src/gdb/inferior.h,v > retrieving revision 1.135 > diff -u -p -r1.135 inferior.h > --- inferior.h =A028 Jun 2009 00:20:22 -0000 =A0 =A0 =A01.135 > +++ inferior.h =A012 Aug 2009 22:28:43 -0000 > @@ -236,6 +236,8 @@ extern void get_last_target_status(ptid_ > > =A0extern void follow_inferior_reset_breakpoints (void); > > +extern void nullify_last_target_wait_ptid (void); > + > =A0/* Throw an error indicating the current thread is running. =A0*/ > =A0extern void error_is_running (void); > > Index: gcore.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > RCS file: /cvs/src/src/gdb/gcore.c,v > retrieving revision 1.34 > diff -u -p -r1.34 gcore.c > --- gcore.c =A0 =A0 2 Jul 2009 17:21:06 -0000 =A0 =A0 =A0 1.34 > +++ gcore.c =A0 =A0 12 Aug 2009 22:28:43 -0000 > @@ -25,10 +25,14 @@ > =A0#include "gdbcore.h" > =A0#include "objfiles.h" > =A0#include "symfile.h" > - > +#include "arch-utils.h" > +#include "completer.h" > +#include "gcore.h" > =A0#include "cli/cli-decode.h" > - > =A0#include "gdb_assert.h" > +#include > +#include "regcache.h" > +#include "regset.h" > > =A0/* The largest amount of memory to read from the target at once. =A0We > =A0 =A0must throttle it to limit the amount of memory used by GDB during > @@ -40,45 +44,27 @@ static enum bfd_architecture default_gco > =A0static unsigned long default_gcore_mach (void); > =A0static int gcore_memory_sections (bfd *); > > -/* Generate a core file from the inferior process. =A0*/ > +/* create_gcore_bfd -- helper for gcore_command (exported). =A0*/ > > -static void > -gcore_command (char *args, int from_tty) > +bfd * > +create_gcore_bfd (char *filename) > =A0{ > - =A0struct cleanup *old_chain; > - =A0char *corefilename, corefilename_buffer[40]; > - =A0asection *note_sec =3D NULL; > - =A0bfd *obfd; > - =A0void *note_data =3D NULL; > - =A0int note_size =3D 0; > - > - =A0/* No use generating a corefile without a target process. =A0*/ > - =A0if (!target_has_execution) > - =A0 =A0noprocess (); > - > - =A0if (args && *args) > - =A0 =A0corefilename =3D args; > - =A0else > - =A0 =A0{ > - =A0 =A0 =A0/* Default corefile name is "core.PID". =A0*/ > - =A0 =A0 =A0sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_pt= id)); > - =A0 =A0 =A0corefilename =3D corefilename_buffer; > - =A0 =A0} > - > - =A0if (info_verbose) > - =A0 =A0fprintf_filtered (gdb_stdout, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Opening corefile '%s' for outp= ut.\n", corefilename); > - > - =A0/* Open the output file. =A0*/ > - =A0obfd =3D bfd_openw (corefilename, default_gcore_target ()); > + =A0bfd *obfd =3D bfd_openw (filename, default_gcore_target ()); > =A0 if (!obfd) > - =A0 =A0error (_("Failed to open '%s' for output."), corefilename); > - > - =A0/* Need a cleanup that will close the file (FIXME: delete it?). =A0*/ > - =A0old_chain =3D make_cleanup_bfd_close (obfd); > - > + =A0 =A0error (_("Failed to open '%s' for output."), filename); > =A0 bfd_set_format (obfd, bfd_core); > =A0 bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ()= ); > + =A0return obfd; > +} > + > +/* write_gcore_file -- helper for gcore_command (exported). =A0*/ > + > +void > +write_gcore_file (bfd *obfd) > +{ > + =A0void *note_data =3D NULL; > + =A0int note_size =3D 0; > + =A0asection *note_sec =3D NULL; > > =A0 /* An external target method must build the notes section. =A0*/ > =A0 note_data =3D target_make_corefile_notes (obfd, ¬e_size); > @@ -107,9 +93,47 @@ gcore_command (char *args, int from_tty) > =A0 if (note_data !=3D NULL && note_size !=3D 0) > =A0 =A0 { > =A0 =A0 =A0 if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, > note_size)) > - =A0 =A0 =A0 warning (_("writing note section (%s)"), bfd_errmsg (bfd_ge= t_error > ())); > + =A0 =A0 =A0 warning (_("writing note section (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bfd_errmsg (bfd_get_error ())); > + =A0 =A0} > +} > + > +/* gcore_command -- implements the 'gcore' command. > + =A0 Generate a core file from the inferior process. =A0*/ > + > +static void > +gcore_command (char *args, int from_tty) > +{ > + =A0struct cleanup *old_chain; > + =A0char *corefilename, corefilename_buffer[40]; > + =A0bfd *obfd; > + > + =A0/* No use generating a corefile without a target process. =A0*/ > + =A0if (!target_has_execution) > + =A0 =A0noprocess (); > + > + =A0if (args && *args) > + =A0 =A0corefilename =3D args; > + =A0else > + =A0 =A0{ > + =A0 =A0 =A0/* Default corefile name is "core.PID". =A0*/ > + =A0 =A0 =A0sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_pt= id)); > + =A0 =A0 =A0corefilename =3D corefilename_buffer; > =A0 =A0 } > > + =A0if (info_verbose) > + =A0 =A0fprintf_filtered (gdb_stdout, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Opening corefile '%s' for outp= ut.\n", corefilename); > + > + =A0/* Open the output file. =A0*/ > + =A0obfd =3D create_gcore_bfd (corefilename); > + > + =A0/* Need a cleanup that will close the file (FIXME: delete it?). =A0*/ > + =A0old_chain =3D make_cleanup_bfd_close (obfd); > + > + =A0/* Call worker function. =A0*/ > + =A0write_gcore_file (obfd); > + > =A0 /* Succeeded. =A0*/ > =A0 fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename); > > @@ -212,6 +236,50 @@ derive_stack_segment (bfd_vma *bottom, b > =A0 return 1; > =A0} > > +/* call_target_sbrk -- > + =A0 helper function for derive_heap_segment and load_core_segment. =A0*/ > + > +static bfd_vma > +call_target_sbrk (int sbrk_arg) > +{ > + =A0struct objfile *sbrk_objf; > + =A0struct gdbarch *gdbarch; > + =A0bfd_vma top_of_heap; > + =A0struct value *target_sbrk_arg; > + =A0struct value *sbrk_fn, *ret; > + =A0bfd_vma tmp; > + > + =A0if (lookup_minimal_symbol ("sbrk", NULL, NULL) !=3D NULL) > + =A0 =A0{ > + =A0 =A0 =A0sbrk_fn =3D find_function_in_inferior ("sbrk", &sbrk_objf); > + =A0 =A0 =A0if (sbrk_fn =3D=3D NULL) > + =A0 =A0 =A0 return (bfd_vma) 0; > + =A0 =A0} > + =A0else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) !=3D NULL) > + =A0 =A0{ > + =A0 =A0 =A0sbrk_fn =3D find_function_in_inferior ("_sbrk", &sbrk_objf); > + =A0 =A0 =A0if (sbrk_fn =3D=3D NULL) > + =A0 =A0 =A0 return (bfd_vma) 0; > + =A0 =A0} > + =A0else > + =A0 =A0return (bfd_vma) 0; > + > + =A0gdbarch =3D get_objfile_arch (sbrk_objf); > + =A0target_sbrk_arg =3D value_from_longest (builtin_type > (gdbarch)->builtin_int, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 sbrk_arg); > + =A0gdb_assert (target_sbrk_arg); > + =A0ret =3D call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg); > + =A0if (ret =3D=3D NULL) > + =A0 =A0return (bfd_vma) 0; > + > + =A0tmp =3D value_as_long (ret); > + =A0if ((LONGEST) tmp <=3D 0 || (LONGEST) tmp =3D=3D 0xffffffff) > + =A0 =A0return (bfd_vma) 0; > + > + =A0top_of_heap =3D tmp; > + =A0return top_of_heap; > +} > + > =A0/* Derive a reasonable heap segment for ABFD by looking at sbrk and > =A0 =A0the static data sections. =A0Store its limits in *BOTTOM and *TOP. > =A0 =A0Return non-zero if successful. =A0*/ > @@ -219,12 +287,10 @@ derive_stack_segment (bfd_vma *bottom, b > =A0static int > =A0derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top) > =A0{ > - =A0struct objfile *sbrk_objf; > =A0 struct gdbarch *gdbarch; > =A0 bfd_vma top_of_data_memory =3D 0; > =A0 bfd_vma top_of_heap =3D 0; > =A0 bfd_size_type sec_size; > - =A0struct value *zero, *sbrk; > =A0 bfd_vma sec_vaddr; > =A0 asection *sec; > > @@ -259,29 +325,9 @@ derive_heap_segment (bfd *abfd, bfd_vma > =A0 =A0 =A0 =A0} > =A0 =A0 } > > - =A0/* Now get the top-of-heap by calling sbrk in the inferior. =A0*/ > - =A0if (lookup_minimal_symbol ("sbrk", NULL, NULL) !=3D NULL) > - =A0 =A0{ > - =A0 =A0 =A0sbrk =3D find_function_in_inferior ("sbrk", &sbrk_objf); > - =A0 =A0 =A0if (sbrk =3D=3D NULL) > - =A0 =A0 =A0 return 0; > - =A0 =A0} > - =A0else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) !=3D NULL) > - =A0 =A0{ > - =A0 =A0 =A0sbrk =3D find_function_in_inferior ("_sbrk", &sbrk_objf); > - =A0 =A0 =A0if (sbrk =3D=3D NULL) > - =A0 =A0 =A0 return 0; > - =A0 =A0} > - =A0else > - =A0 =A0return 0; > - > - =A0gdbarch =3D get_objfile_arch (sbrk_objf); > - =A0zero =3D value_from_longest (builtin_type (gdbarch)->builtin_int, 0); > - =A0gdb_assert (zero); > - =A0sbrk =3D call_function_by_hand (sbrk, 1, &zero); > - =A0if (sbrk =3D=3D NULL) > + =A0top_of_heap =3D call_target_sbrk (0); > + =A0if (top_of_heap =3D=3D (bfd_vma) 0) > =A0 =A0 return 0; > - =A0top_of_heap =3D value_as_long (sbrk); > > =A0 /* Return results. =A0*/ > =A0 if (top_of_heap > top_of_data_memory) > @@ -299,13 +345,15 @@ static void > =A0make_output_phdrs (bfd *obfd, asection *osec, void *ignored) > =A0{ > =A0 int p_flags =3D 0; > - =A0int p_type; > + =A0int p_type =3D 0; > > =A0 /* FIXME: these constants may only be applicable for ELF. =A0*/ > =A0 if (strncmp (bfd_section_name (obfd, osec), "load", 4) =3D=3D 0) > =A0 =A0 p_type =3D PT_LOAD; > - =A0else > + =A0else if (strncmp (bfd_section_name (obfd, osec), "note", 4) =3D=3D 0) > =A0 =A0 p_type =3D PT_NOTE; > + =A0else > + =A0 =A0p_type =3D PT_NULL; > > =A0 p_flags |=3D PF_R; =A0 =A0 /* Segment is readable. =A0*/ > =A0 if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY)) > @@ -516,6 +564,141 @@ gcore_memory_sections (bfd *obfd) > =A0 return 1; > =A0} > > +struct load_core_args_params { > + =A0int from_tty; > + =A0bfd_vma top_of_heap; > +}; > + > +/* load_core_segments -- iterator function for bfd_map_over_sections. = =A0*/ > + > +static void > +load_core_segment (bfd *abfd, asection *asect, void *arg) > +{ > + =A0struct load_core_args_params *params =3D arg; > + =A0struct cleanup *old_chain; > + =A0char *memhunk; > + =A0int ret; > + > + =A0if ((bfd_section_size (abfd, asect) > 0) && > + =A0 =A0 =A0(bfd_get_section_flags (abfd, asect) & SEC_LOAD) && > + =A0 =A0 =A0!(bfd_get_section_flags (abfd, asect) & SEC_READONLY)) > + =A0 =A0{ > + =A0 =A0 =A0if (info_verbose && params->from_tty) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 printf_filtered (_("Load core section %s"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bfd_section_name (ab= fd, asect)); > + =A0 =A0 =A0 =A0 printf_filtered (_(", vma 0x%08lx to 0x%08lx"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long) bfd_= section_vma (abfd, asect), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long) bfd_= section_vma (abfd, asect) + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(int) bfd_section_si= ze (abfd, asect)); > + =A0 =A0 =A0 =A0 printf_filtered (_(", size =3D %d"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(int) bfd_section_si= ze (abfd, asect)); > + =A0 =A0 =A0 =A0 printf_filtered (_(".\n")); > + =A0 =A0 =A0 } > + =A0 =A0 =A0/* Fixme cleanup? */ > + =A0 =A0 =A0memhunk =3D xmalloc (bfd_section_size (abfd, asect)); > + =A0 =A0 =A0bfd_get_section_contents (abfd, asect, memhunk, 0, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bfd_section= _size (abfd, asect)); > + =A0 =A0 =A0if ((ret =3D target_write_memory (bfd_section_vma (abfd, ase= ct), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= memhunk, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= bfd_section_size (abfd, asect))) !=3D 0) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 print_sys_errmsg ("load_core_segment", ret); > + =A0 =A0 =A0 =A0 if ((LONGEST) params->top_of_heap < > + =A0 =A0 =A0 =A0 =A0 =A0 (LONGEST) bfd_section_vma (abfd, asect) + > + =A0 =A0 =A0 =A0 =A0 =A0 (LONGEST) bfd_section_size (abfd, asect)) > + =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 =A0 int increment =3D bfd_section_vma (abfd, asect)= + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bfd_section_size (abfd, asect) - params->to= p_of_heap; > + > + =A0 =A0 =A0 =A0 =A0 =A0 params->top_of_heap =3D call_target_sbrk (incre= ment); > + =A0 =A0 =A0 =A0 =A0 =A0 if (params->top_of_heap =3D=3D 0) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error ("sbrk failed, TOH =3D 0x%08lx", para= ms->top_of_heap); > + =A0 =A0 =A0 =A0 =A0 =A0 else > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printf_filtered ("Increase TOH to 0x%08lx a= nd retry.\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigne= d long) params->top_of_heap); > + =A0 =A0 =A0 =A0 =A0 =A0 if (target_write_memory (bfd_section_vma (abfd,= asect), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0memhunk, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0bfd_section_size (abfd, asect)) !=3D 0) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 error ("Nope, still failed."); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 } > + =A0 =A0 =A0xfree (memhunk); > + =A0 =A0} > +} > + > +/* load_corefile -- reads a corefile, copies its memory sections > + =A0 into target memory, and its registers into target regcache. =A0*/ > + > +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? > + =A0struct load_core_args_params params; > + =A0struct bfd_section *regsect; > + =A0const struct regset *regset; > + =A0struct regcache *regcache; > + =A0struct cleanup *old_chain; > + =A0struct gdbarch *gdbarch; > + =A0char *scratch_path; > + =A0int scratch_chan; > + =A0char *contents; > + =A0bfd *core_bfd; > + =A0int size; > + > + =A0scratch_chan =3D openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 O_BINARY | O_RDONLY | O_LAR= GEFILE, &scratch_path); > + =A0if (scratch_chan < 0) > + =A0 =A0perror_with_name (filename); > + > + =A0core_bfd =3D bfd_fdopenr (scratch_path, gnutarget, scratch_chan); > + =A0old_chain =3D make_cleanup_bfd_close (core_bfd); > + =A0if (!core_bfd) > + =A0 =A0perror_with_name (scratch_path); > + > + =A0if (!bfd_check_format (core_bfd, bfd_core)) > + =A0 =A0error (_("\"%s\" is not a core file: %s"), > + =A0 =A0 =A0 =A0 =A0filename, bfd_errmsg (bfd_get_error ())); > + > + =A0params.from_tty =3D from_tty; > + =A0params.top_of_heap =3D call_target_sbrk (0); > + =A0if (params.top_of_heap =3D=3D 0) > + =A0 =A0error (_("Couldn't get sbrk.")); > + > + =A0bfd_map_over_sections (core_bfd, load_core_segment, (void *) ¶ms= ); > + =A0/* Now need to get/set registers. =A0*/ > + =A0regsect =3D bfd_get_section_by_name (core_bfd, ".reg"); > + > + =A0if (!regsect) > + =A0 =A0error (_("Couldn't find .reg section.")); > + > + =A0size =3D bfd_section_size (core_bfd, regsect); > + =A0contents =3D alloca (size); > + =A0bfd_get_section_contents (core_bfd, regsect, contents, 0, size); > + > + =A0/* See FIXME kettenis/20031023 comment in corelow.c */ > + =A0gdbarch =3D gdbarch_from_bfd (core_bfd); > + > + =A0if (gdbarch && gdbarch_regset_from_core_section_p (gdbarch)) > + =A0 =A0{ > + =A0 =A0 =A0regset =3D gdbarch_regset_from_core_section (gdbarch, ".reg"= , size); > + =A0 =A0 =A0if (!regset) > + =A0 =A0 =A0 error (_("Failed to allocate regset.")); > + > + =A0 =A0 =A0registers_changed (); > + =A0 =A0 =A0regcache =3D get_current_regcache (); > + =A0 =A0 =A0regset->supply_regset (regset, regcache, -1, contents, size); > + =A0 =A0 =A0reinit_frame_cache (); > + =A0 =A0 =A0target_store_registers (regcache, -1); > + =A0 =A0} > + =A0else > + =A0 =A0error (_("Failed to get regset from core section")); > + > + =A0discard_cleanups (old_chain); > + =A0return core_bfd; > +} > + > =A0/* Provide a prototype to silence -Wmissing-prototypes. =A0*/ > =A0extern initialize_file_ftype _initialize_gcore; > > Index: record.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > RCS file: /cvs/src/src/gdb/record.c,v > retrieving revision 1.11 > diff -u -p -r1.11 record.c > --- record.c =A0 =A08 Aug 2009 01:57:44 -0000 =A0 =A0 =A0 1.11 > +++ record.c =A0 =A012 Aug 2009 22:28:43 -0000 > @@ -23,15 +23,24 @@ > =A0#include "gdbthread.h" > =A0#include "event-top.h" > =A0#include "exceptions.h" > +#include "completer.h" > =A0#include "record.h" > > +#include > =A0#include > +#include > +#include "elf-bfd.h" > +#include "gdbcore.h" > +#include > +#include "gcore.h" > > =A0#define DEFAULT_RECORD_INSN_MAX_NUM =A0 =A0200000 > > =A0#define RECORD_IS_REPLAY \ > =A0 =A0 =A0(record_list->next || execution_direction =3D=3D EXEC_REVERSE) > > +#define RECORD_FILE_MAGIC =A0 =A0 =A0htonl(0x20090726) /* Host to networ= k order > */ > + > =A0/* These are the core struct of record function. > > =A0 =A0An record_entry is a record of the value change of a register > @@ -146,6 +155,11 @@ record_list_release (struct record_entry > > =A0 if (rec !=3D &record_first) > =A0 =A0 xfree (rec); > + > + =A0record_list =3D &record_first; > + =A0record_arch_list_tail =3D NULL; > + =A0record_arch_list_tail =3D NULL; > + =A0record_insn_num =3D 0; > =A0} This function have other function except clear all record_list_release. I will post how to clear all record_list in cmd_record_load. > > =A0static void > @@ -241,7 +255,7 @@ record_arch_list_add_reg (struct regcach > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0num); > > =A0 rec =3D (struct record_entry *) xmalloc (sizeof (struct record_entry)= ); > - =A0rec->u.reg.val =3D (gdb_byte *) xmalloc (MAX_REGISTER_SIZE); > + =A0rec->u.reg.val =3D (gdb_byte *) xcalloc (1, MAX_REGISTER_SIZE); > =A0 rec->prev =3D NULL; > =A0 rec->next =3D NULL; > =A0 rec->type =3D record_reg; > @@ -416,6 +430,95 @@ record_gdb_operation_disable_set (void) > =A0 return old_cleanups; > =A0} > > +static inline void > +record_exec_entry (struct regcache *regcache, struct gdbarch *gdbarch, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct record_entry *entry) > +{ > + =A0switch (entry->type) > + =A0 =A0{ > + =A0 =A0case record_reg: /* reg */ > + =A0 =A0 =A0{ > + =A0 =A0 =A0 =A0gdb_byte reg[MAX_REGISTER_SIZE]; > + > + =A0 =A0 =A0 =A0if (record_debug > 1) > + =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Process rec= ord: record_reg %s to " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"inferior nu= m =3D %d.\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0host_address= _to_string (entry), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0entry->u.reg= .num); > + > + =A0 =A0 =A0 =A0memset (reg, 0, sizeof (reg)); > + =A0 =A0 =A0 =A0regcache_cooked_read (regcache, entry->u.reg.num, reg); > + =A0 =A0 =A0 =A0regcache_cooked_write (regcache, entry->u.reg.num, > entry->u.reg.val); > + =A0 =A0 =A0 =A0memcpy (entry->u.reg.val, reg, MAX_REGISTER_SIZE); > + =A0 =A0 =A0} > + =A0 =A0 =A0break; > + > + =A0 =A0case record_mem: /* mem */ > + =A0 =A0 =A0{ > + =A0 =A0 =A0 /* Nothing to do if the entry is flagged not_accessible. = =A0*/ > + =A0 =A0 =A0 =A0if (!record_list->u.mem.mem_entry_not_accessible) > + =A0 =A0 =A0 =A0 =A0{ > + =A0 =A0 =A0 =A0 =A0 =A0gdb_byte *mem =3D alloca (entry->u.mem.len); > + > + =A0 =A0 =A0 =A0 =A0 =A0if (record_debug > 1) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Pro= cess record: record_mem %s to " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"inf= erior addr =3D %s len =3D %d.\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0host= _address_to_string (entry), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0padd= ress (gdbarch, entry->u.mem.addr), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reco= rd_list->u.mem.len); > + > + =A0 =A0 =A0 =A0 =A0 =A0if (target_read_memory (entry->u.mem.addr, mem, > entry->u.mem.len)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0{ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (execution_direction =3D=3D EXEC_REVE= RSE) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ When it works with core file, exec forware will get some error in lib, it need change error to warning too. > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Read failed -- > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flag entry as not_accessible= . =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.mem_entry_not= _accessible =3D 1; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0warning (_("Process record: = error reading memory at " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr = =3D %s len =3D %d."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddress (g= dbarch, entry->u.mem.addr), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 entry->u.me= m.len); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0error (_("Process record: error read= ing memory at " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr =3D %s len = =3D %d."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddress (gdbarch, entr= y->u.mem.addr), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0entry->u.mem.len); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0 =A0 =A0else > + =A0 =A0 =A0 =A0 =A0 =A0 =A0{ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (target_write_memory (entry->u.mem.ad= dr, > entry->u.mem.val, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 entry->u.mem.len)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (execution_direction =3D=3D E= XEC_REVERSE) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Write failed -- > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flag entry as not_ac= cessible. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.mem_e= ntry_not_accessible =3D 1; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0warning (_("Process = record: error writing memory > at " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= "addr =3D %s len =3D %d."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pad= dress (gdbarch, entry->u.mem.addr), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ent= ry->u.mem.len); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0error (_("Process record: er= ror writing memory at " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr =3D %= s len =3D %d."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddress (gdbar= ch, entry->u.mem.addr), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0entry->u.mem.len= ); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memcpy (entry->u.mem.val, mem, entry->u= .mem.len); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0} > + =A0 =A0 =A0break; > + =A0 =A0} > +} > + > =A0static void > =A0record_open (char *name, int from_tty) > =A0{ > @@ -712,76 +815,9 @@ record_wait (struct target_ops *ops, > =A0 =A0 =A0 =A0 =A0 =A0 =A0break; > =A0 =A0 =A0 =A0 =A0 =A0} > > - =A0 =A0 =A0 =A0 /* Set ptid, register and memory according to record_li= st. =A0*/ > - =A0 =A0 =A0 =A0 if (record_list->type =3D=3D record_reg) > - =A0 =A0 =A0 =A0 =A0 { > - =A0 =A0 =A0 =A0 =A0 =A0 /* reg */ > - =A0 =A0 =A0 =A0 =A0 =A0 gdb_byte reg[MAX_REGISTER_SIZE]; > - =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug > 1) > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Pr= ocess record: record_reg %s to " > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "in= ferior num =3D %d.\n", > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hos= t_address_to_string (record_list), > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rec= ord_list->u.reg.num); > - =A0 =A0 =A0 =A0 =A0 =A0 regcache_cooked_read (regcache, record_list->u.= reg.num, reg); > - =A0 =A0 =A0 =A0 =A0 =A0 regcache_cooked_write (regcache, record_list->u= .reg.num, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= record_list->u.reg.val); > - =A0 =A0 =A0 =A0 =A0 =A0 memcpy (record_list->u.reg.val, reg, MAX_REGIST= ER_SIZE); > - =A0 =A0 =A0 =A0 =A0 } > - =A0 =A0 =A0 =A0 else if (record_list->type =3D=3D record_mem) > - =A0 =A0 =A0 =A0 =A0 { > - =A0 =A0 =A0 =A0 =A0 =A0 /* mem */ > - =A0 =A0 =A0 =A0 =A0 =A0 /* Nothing to do if the entry is flagged not_ac= cessible. =A0*/ > - =A0 =A0 =A0 =A0 =A0 =A0 if (!record_list->u.mem.mem_entry_not_accessibl= e) > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 { > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gdb_byte *mem =3D alloca (record_list->= u.mem.len); > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug > 1) > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 "Process record: record_mem %s to " > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 "inferior addr =3D %s len =3D %d.\n", > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 host_address_to_string > (record_list), > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 paddress (gdbarch, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 record_list->u.mem.addr), > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 record_list->u.mem.len); > - > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (target_read_memory (record_list->u.= mem.addr, mem, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 record_list->u.mem.len)) > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (execution_direction !=3D EX= EC_REVERSE) > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: e= rror reading memory at " > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"addr = =3D %s len =3D %d."), > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddress (gd= barch, record_list->u.mem.addr), > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list-= >u.mem.len); > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Read failed -- > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flag entry as not_ac= cessible. =A0*/ > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_list->u.mem.mem_entr= y_not_accessible =3D 1; > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (target_write_memory (record= _list->u.mem.addr, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0record_list->u.mem.val, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0record_list->u.mem.len)) > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (execution_direction= !=3D EXEC_REVERSE) > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process r= ecord: error writing memory > at " > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= "addr =3D %s len =3D %d."), > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0padd= ress (gdbarch, > record_list->u.mem.addr), > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reco= rd_list->u.mem.len); > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Write failed -- > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flag entry a= s not_accessible. =A0*/ > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_list->u.mem.= mem_entry_not_accessible =3D 1; > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memcpy (record_list->u.= mem.val, mem, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_= list->u.mem.len); > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > - =A0 =A0 =A0 =A0 =A0 } > - =A0 =A0 =A0 =A0 else > + =A0 =A0 =A0 =A0 =A0record_exec_entry (regcache, gdbarch, record_list); > + > + =A0 =A0 =A0 =A0 if (record_list->type =3D=3D record_end) > =A0 =A0 =A0 =A0 =A0 =A0{ > =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug > 1) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, > @@ -999,6 +1035,7 @@ record_store_registers (struct target_op > > =A0 =A0 =A0 record_registers_change (regcache, regno); > =A0 =A0 } > + > =A0 record_beneath_to_store_registers (record_beneath_to_store_registers_= ops, > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0regcache, regno); > =A0} > @@ -1153,6 +1190,448 @@ cmd_record_start (char *args, int from_t > =A0 execute_command ("target record", from_tty); > =A0} > > +/* Record log save-file format > + =A0 Version 1 > + > + =A0 =A0 Header: > + =A0 =A0 =A0 4 bytes: magic number RECORD_FILE_MAGIC. > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0NOTE: be sure to change whenever this fi= le format changes! > + > + =A0 =A0 Records: > + =A0 =A0 =A0record_end: > + =A0 =A0 =A0 1 byte: =A0record type (record_end) > + =A0 =A0 =A0record_reg: > + =A0 =A0 =A0 1 byte: =A0record type (record_reg) > + =A0 =A0 =A0 8 bytes: register id (network byte order) > + =A0 =A0 =A016 bytes: register value (target byte order) > + =A0 =A0 =A0record_mem: > + =A0 =A0 =A0 1 byte: =A0record type (record_mem) > + =A0 =A0 =A0 8 bytes: memory address (network byte order) > + =A0 =A0 =A0 8 bytes: memory length (network byte order) > + =A0 =A0 =A0 n bytes: memory value (n =3D=3D memory length, target byte = order) > + > + =A0 Version 2 (proposed) > + > + =A0 =A0 Header: > + =A0 =A0 =A0 4 bytes: magic number RECORD_FILE_MAGIC. > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0NOTE: be sure to change whenever this fi= le format changes! > + =A0 =A0 =A0 n bytes: architecture... > + =A0 =A0 =A0 4 bytes: size of register snapshot > + =A0 =A0 =A0 n bytes: register snapshot > + =A0 =A0 =A0 4 bytes: number of section crcs > + =A0 =A0 =A0 n bytes: section names with crcs > + > + =A0 =A0 Records: > + =A0 =A0 =A0 See version 1. > + */ > + > +/* bfdcore_write -- write bytes into a core file section. =A0*/ > + > +static int > +bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offse= t) > +{ > + =A0int ret =3D bfd_set_section_contents (obfd, osec, buf, *offset, len); > + > + =A0if (ret) > + =A0 =A0*offset +=3D len; > + =A0return ret; > +} > + > +/* Dump the execution log to a file. =A0*/ > + > +static void > +cmd_record_dump (char *args, int from_tty) > +{ > + =A0char *recfilename, recfilename_buffer[40]; > + =A0int recfd; > + =A0struct record_entry *cur_record_list; > + =A0uint32_t magic; > + =A0struct regcache *regcache; > + =A0struct gdbarch *gdbarch; > + =A0struct cleanup *old_cleanups; > + =A0struct cleanup *set_cleanups; > + =A0bfd *obfd; > + =A0int dump_size =3D 0; > + =A0asection *osec =3D NULL; > + =A0struct record_entry *p; > + =A0int bfd_offset =3D 0; > + > + > + =A0if (current_target.to_stratum !=3D record_stratum) > + =A0 =A0error (_("Process record is not started.\n")); > + > + =A0if (args && *args) > + =A0 =A0recfilename =3D args; > + =A0else > + =A0 =A0{ > + =A0 =A0 =A0/* Default recfile name is "rec.PID". =A0*/ > + =A0 =A0 =A0sprintf (recfilename_buffer, "rec.%d", PIDGET (inferior_ptid= )); > + =A0 =A0 =A0recfilename =3D recfilename_buffer; > + =A0 =A0} > + > + =A0/* Open the dump file. =A0*/ > + =A0if (record_debug) > + =A0 =A0fprintf_filtered (gdb_stdlog, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Saving recording to file '%s= '\n"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 recfilename); > + > + =A0/* Open the output file. =A0*/ > + =A0obfd =3D create_gcore_bfd (recfilename); > + > + =A0/* Need a cleanup that will close the file (FIXME: delete it?). =A0*/ > + =A0old_cleanups =3D make_cleanup_bfd_close (obfd); > + > + =A0/* Save the current record entry to "cur_record_list". =A0*/ > + =A0cur_record_list =3D record_list; > + > + =A0/* Get the values of regcache and gdbarch. =A0*/ > + =A0regcache =3D get_current_regcache (); > + =A0gdbarch =3D get_regcache_arch (regcache); > + > + =A0/* Disable the GDB operation record. =A0*/ > + =A0set_cleanups =3D record_gdb_operation_disable_set (); > + > + =A0/* Reverse execute to the begin of record list. =A0*/ > + =A0for (; record_list && record_list !=3D &record_first; > + =A0 =A0 =A0 record_list =3D record_list->prev) > + =A0 =A0record_exec_entry (regcache, gdbarch, record_list); > + > + =A0/* Compute the size needed for the extra bfd section. =A0*/ > + =A0dump_size =3D 4; =A0 =A0 =A0 /* magic cookie */ > + =A0for (p =3D &record_first; p; p =3D p->next) > + =A0 =A0switch (p->type) > + =A0 =A0 =A0{ > + =A0 =A0 =A0case record_end: > + =A0 =A0 =A0 dump_size +=3D 1; > + =A0 =A0 =A0 break; > + =A0 =A0 =A0case record_reg: > + =A0 =A0 =A0 dump_size +=3D 1 + 8 + MAX_REGISTER_SIZE; > + =A0 =A0 =A0 break; > + =A0 =A0 =A0case record_mem: > + =A0 =A0 =A0 dump_size +=3D 1 + 8 + 8 + p->u.mem.len; > + =A0 =A0 =A0 break; > + =A0 =A0 =A0} > + > + =A0/* Make the new bfd section. =A0*/ > + =A0osec =3D bfd_make_section_anyway (obfd, "precord"); > + =A0bfd_set_section_size (obfd, osec, dump_size); > + =A0bfd_set_section_vma (obfd, osec, 0); > + =A0bfd_section_lma (obfd, osec) =3D 0; > + =A0bfd_set_section_flags (obfd, osec, SEC_ALLOC | SEC_HAS_CONTENTS); > + > + =A0/* Save corefile state. =A0*/ > + =A0write_gcore_file (obfd); I am not sure it is a better idea that reverse and gcore. > + > + =A0/* Write out the record log (modified Hui method). =A0*/ > + =A0/* Write the magic code. =A0*/ > + =A0magic =3D RECORD_FILE_MAGIC; > + =A0if (record_debug) > + =A0 =A0fprintf_filtered (gdb_stdlog, _("\ > + =A0Writing 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 magic); > + =A0if (!bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset)) > + =A0 =A0error (_("Failed to write 'magic' to %s (%s)"), > + =A0 =A0 =A0 =A0 =A0recfilename, bfd_errmsg (bfd_get_error ())); > + > + =A0/* Dump the entries into the new bfd section. =A0*/ > + =A0for (p =3D &record_first; p; p =3D p->next) > + =A0 =A0{ > + =A0 =A0 =A0uint8_t tmpu8; > + =A0 =A0 =A0uint64_t tmpu64; > + > + =A0 =A0 =A0tmpu8 =3D p->type; > + =A0 =A0 =A0if (!bfdcore_write (obfd, osec, &tmpu8, sizeof (tmpu8), &bfd= _offset)) > + =A0 =A0 =A0 error (_("Failed to write 'type' to %s (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename, bfd_errmsg (bfd_get_error ())); > + > + =A0 =A0 =A0switch (p->type) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 case record_reg: /* reg */ > + =A0 =A0 =A0 =A0 tmpu64 =3D p->u.reg.num; > + =A0 =A0 =A0 =A0 if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) > + =A0 =A0 =A0 =A0 =A0 tmpu64 =3D bswap_64 (tmpu64); > + > + =A0 =A0 =A0 =A0 if (record_debug) > + =A0 =A0 =A0 =A0 =A0 fprintf_filtered (gdb_stdlog, _("\ > + =A0Writing register %d val 0x%016llx (1 plus 8 plus %d bytes)\n"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 p->u.reg.num, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *(ULONGEST *) p= ->u.reg.val, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 MAX_REGISTER_SI= ZE); > + =A0 =A0 =A0 =A0 /* FIXME: register num does not need 8 bytes. =A0*/ > + =A0 =A0 =A0 =A0 if (!bfdcore_write (obfd, osec, &tmpu64, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sizeof (tmpu64)= , &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 error (_("Failed to write regnum to %s (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename, bfd_errmsg (bfd_get_err= or ())); > + > + =A0 =A0 =A0 =A0 /* FIXME: add a len field, and write the smaller value.= =A0*/ > + =A0 =A0 =A0 =A0 if (!bfdcore_write (obfd, osec, p->u.reg.val, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 MAX_REGISTER_SIZE, &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 error (_("Failed to write regval to %s (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename, bfd_errmsg (bfd_get_err= or ())); > + =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 case record_mem: /* mem */ > + =A0 =A0 =A0 =A0 tmpu64 =3D p->u.mem.addr; > + =A0 =A0 =A0 =A0 if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) > + =A0 =A0 =A0 =A0 =A0 tmpu64 =3D bswap_64 (tmpu64); > + > + =A0 =A0 =A0 =A0 if (record_debug) > + =A0 =A0 =A0 =A0 =A0 fprintf_filtered (gdb_stdlog, _("\ > + =A0Writing memory 0x%08x (1 plus 8 plus 8 bytes plus %d bytes)\n"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (unsigned int) = p->u.mem.addr, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 p->u.mem.len); > + =A0 =A0 =A0 =A0 if (!bfdcore_write (obfd, osec, &tmpu64, sizeof (tmpu64= ), > &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 error (_("Failed to write memaddr to %s (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename, bfd_errmsg (bfd_get_err= or ())); > + > + =A0 =A0 =A0 =A0 tmpu64 =3D p->u.mem.len; > + =A0 =A0 =A0 =A0 if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) > + =A0 =A0 =A0 =A0 =A0 tmpu64 =3D bswap_64 (tmpu64); > + > + =A0 =A0 =A0 =A0 /* FIXME: len does not need 8 bytes. =A0*/ > + =A0 =A0 =A0 =A0 if (!bfdcore_write (obfd, osec, &tmpu64, sizeof (tmpu64= ), > &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 error (_("Failed to write memlen to %s (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename, bfd_errmsg (bfd_get_err= or ())); > + > + =A0 =A0 =A0 =A0 if (!bfdcore_write (obfd, osec, p->u.mem.val, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 p->u.mem.len, &= bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 error (_("Failed to write memval to %s (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename, bfd_errmsg (bfd_get_err= or ())); > + =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 case record_end: > + =A0 =A0 =A0 =A0 /* FIXME: record the contents of record_end rec. =A0*/ > + =A0 =A0 =A0 =A0 if (record_debug) > + =A0 =A0 =A0 =A0 =A0 fprintf_filtered (gdb_stdlog, _("\ > + =A0Writing record_end (1 byte)\n")); > + =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 } > + =A0 =A0} > + > + =A0/* Now forward-execute back to the saved entry. =A0*/ > + =A0for (record_list =3D &record_first; > + =A0 =A0 =A0 record_list && record_list !=3D cur_record_list; > + =A0 =A0 =A0 record_list =3D record_list->next) > + =A0 =A0record_exec_entry (regcache, gdbarch, record_list); > + > + =A0/* Clean-ups will close the output file and free malloc memory. =A0*/ > + =A0do_cleanups (old_cleanups); > + > + =A0/* Succeeded. =A0*/ > + =A0fprintf_filtered (gdb_stdout, "Saved recfile %s.\n", recfilename); > +} > + > +/* bfdcore_read -- read bytes from a core file section. =A0*/ > + > +static int > +bfdcore_read (bfd *obfd, asection *osec, void *buf, int len, int *offset) > +{ > + =A0int ret =3D bfd_get_section_contents (obfd, osec, buf, *offset, len); > + > + =A0if (ret) > + =A0 =A0*offset +=3D len; > + =A0return ret; > +} > + > +/* Load the execution log from a file. =A0*/ > + > +static void > +cmd_record_load (char *args, int from_tty) > +{ > + =A0int recfd; > + =A0uint32_t magic; > + =A0struct cleanup *old_cleanups; > + =A0struct cleanup *old_cleanups2; > + =A0struct record_entry *rec; > + =A0int insn_number =3D 0; > + =A0bfd *core_bfd; > + =A0asection *osec; > + > + =A0if (!args || (args && !*args)) > + =A0 =A0error (_("Argument for filename required.\n")); > + > + =A0/* Open the load file. =A0*/ > + =A0if (record_debug) > + =A0 =A0fprintf_filtered (gdb_stdlog, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Restoring recording from fil= e '%s'\n"), args); > + > + =A0/* Restore corefile regs and mem sections. =A0*/ > + =A0core_bfd =3D load_corefile (args, from_tty); > + =A0old_cleanups =3D make_cleanup_bfd_close (core_bfd); > + > + =A0/* Now need to find our special note section. =A0*/ > + =A0osec =3D bfd_get_section_by_name (core_bfd, "null0"); > + =A0printf_filtered ("Find precord section %s.\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0osec ? "succeeded" : "failed"); > + > + =A0if (osec) > + =A0 =A0{ > + =A0 =A0 =A0int i, len; > + =A0 =A0 =A0int bfd_offset =3D 0; > + > + =A0 =A0 =A0if (record_debug) > + =A0 =A0 =A0 fprintf_filtered (gdb_stdlog, "osec name =3D '%s'\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bfd_section_name (core_= bfd, osec)); > + =A0 =A0 =A0len =3D (int) bfd_section_size (core_bfd, osec); > + =A0 =A0 =A0printf_filtered ("osec size =3D %d\n", len); > + > + =A0 =A0 =A0/* Check the magic code. =A0*/ > + =A0 =A0 =A0if (!bfdcore_read (core_bfd, osec, &magic, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sizeof (magic), &bfd_off= set)) > + =A0 =A0 =A0 error (_("Failed to read 'magic' from %s (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0args, bfd_errmsg (bfd_get_error ())); > + > + =A0 =A0 =A0if (magic !=3D RECORD_FILE_MAGIC) > + =A0 =A0 =A0 error (_("'%s', version mis-match / file format error."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0args); > + > + =A0 =A0 =A0if (record_debug) > + =A0 =A0 =A0 fprintf_filtered (gdb_stdlog, _("\ > + =A0Reading 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 magic); > + =A0 =A0 =A0if (current_target.to_stratum !=3D record_stratum) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 /* FIXME need cleanup! =A0We might error out. =A0*/ > + =A0 =A0 =A0 =A0 cmd_record_start (NULL, from_tty); > + =A0 =A0 =A0 =A0 printf_unfiltered (_("Auto start process record.\n")); > + =A0 =A0 =A0 } > + > + =A0 =A0 =A0/* Free any existing record log, and load the entries in > + =A0 =A0 =A0 =A0core_bfd to the new record log. =A0*/ > + =A0 =A0 =A0record_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 !=3D &record_first; record_list =3D record_list->prev) record_exec_entry (regcache, gdbarch, record_list); //release all entry record_list_release_next (); } > + =A0 =A0 =A0old_cleanups2 =3D make_cleanup (record_message_cleanups, 0); > + > + =A0 =A0 =A0while (1) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 uint8_t tmpu8; > + =A0 =A0 =A0 =A0 uint64_t tmpu64; > + > + =A0 =A0 =A0 =A0 /* FIXME: Check offset for end-of-section. =A0*/ > + =A0 =A0 =A0 =A0 if (!bfdcore_read (core_bfd, osec, &tmpu8, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sizeof (tmpu8), = &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 break; > + > + =A0 =A0 =A0 =A0 switch (tmpu8) > + =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 case record_reg: /* reg */ > + =A0 =A0 =A0 =A0 =A0 =A0 /* FIXME: abstract out into an 'insert' functio= n. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 rec =3D (struct record_entry *) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xmalloc (sizeof (struct record_entry)); > + =A0 =A0 =A0 =A0 =A0 =A0 rec->u.reg.val =3D (gdb_byte *) xcalloc (1, MAX= _REGISTER_SIZE); > + =A0 =A0 =A0 =A0 =A0 =A0 rec->prev =3D NULL; > + =A0 =A0 =A0 =A0 =A0 =A0 rec->next =3D NULL; > + =A0 =A0 =A0 =A0 =A0 =A0 rec->type =3D record_reg; > + =A0 =A0 =A0 =A0 =A0 =A0 /* Get num. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 /* FIXME: register num does not need 8 bytes. = =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 if (!bfdcore_read (core_bfd, osec, &tmpu64, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sizeof (= tmpu64), &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Failed to read regnum from %s (%s= )"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0args, bfd_errmsg (bfd_get_er= ror ())); > + > + =A0 =A0 =A0 =A0 =A0 =A0 if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tmpu64 =3D bswap_64 (tmpu64); > + =A0 =A0 =A0 =A0 =A0 =A0 rec->u.reg.num =3D tmpu64; > + > + =A0 =A0 =A0 =A0 =A0 =A0 /* Get val. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 if (!bfdcore_read (core_bfd, osec, rec->u.reg.v= al, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0MAX_REGI= STER_SIZE, &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Failed to read regval from =A0%s = (%s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0args, bfd_errmsg (bfd_get_er= ror ())); > + > + =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_filtered (gdb_stdlog, _("\ > + =A0Reading register %d val 0x%016llx (1 plus 8 plus %d bytes)\n"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rec->u.= reg.num, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *(ULONG= EST *) rec->u.reg.val, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 MAX_REG= ISTER_SIZE); > + =A0 =A0 =A0 =A0 =A0 =A0 record_arch_list_add (rec); > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + > + =A0 =A0 =A0 =A0 =A0 case record_mem: /* mem */ > + =A0 =A0 =A0 =A0 =A0 =A0 rec =3D (struct record_entry *) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xmalloc (sizeof (struct record_entry)); > + =A0 =A0 =A0 =A0 =A0 =A0 rec->prev =3D NULL; > + =A0 =A0 =A0 =A0 =A0 =A0 rec->next =3D NULL; > + =A0 =A0 =A0 =A0 =A0 =A0 rec->type =3D record_mem; > + =A0 =A0 =A0 =A0 =A0 =A0 /* Get addr. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 if (!bfdcore_read (core_bfd, osec, &tmpu64, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sizeof (= tmpu64), &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Failed to read memaddr from %s (%= s)"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0args, bfd_errmsg (bfd_get_er= ror ())); > + =A0 =A0 =A0 =A0 =A0 =A0 if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tmpu64 =3D bswap_64 (tmpu64); > + =A0 =A0 =A0 =A0 =A0 =A0 rec->u.mem.addr =3D tmpu64; > + > + =A0 =A0 =A0 =A0 =A0 =A0 /* Get len. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 /* FIXME: len does not need 8 bytes. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 if (!bfdcore_read (core_bfd, osec, &tmpu64, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sizeof (= tmpu64), &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Failed to read memlen from %s (%s= )"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0args, bfd_errmsg (bfd_get_er= ror ())); > + =A0 =A0 =A0 =A0 =A0 =A0 if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tmpu64 =3D bswap_64 (tmpu64); > + =A0 =A0 =A0 =A0 =A0 =A0 rec->u.mem.len =3D tmpu64; > + > + =A0 =A0 =A0 =A0 =A0 =A0 rec->u.mem.mem_entry_not_accessible =3D 0; > + =A0 =A0 =A0 =A0 =A0 =A0 rec->u.mem.val =3D (gdb_byte *) xmalloc (rec->u= .mem.len); > + =A0 =A0 =A0 =A0 =A0 =A0 /* Get val. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 if (!bfdcore_read (core_bfd, osec, rec->u.mem.v= al, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rec->u.m= em.len, &bfd_offset)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Failed to read memval from %s (%s= )"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0args, bfd_errmsg (bfd_get_er= ror ())); > + =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_filtered (gdb_stdlog, _("\ > + =A0Reading memory 0x%08x (1 plus 8 plus %d bytes)\n"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (unsign= ed int) rec->u.mem.addr, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rec->u.= mem.len); > + =A0 =A0 =A0 =A0 =A0 =A0 record_arch_list_add (rec); > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + > + =A0 =A0 =A0 =A0 =A0 case record_end: /* end */ > + =A0 =A0 =A0 =A0 =A0 =A0 /* FIXME: restore the contents of record_end re= c. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 rec =3D (struct record_entry *) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xmalloc (sizeof (struct record_entry)); > + =A0 =A0 =A0 =A0 =A0 =A0 rec->prev =3D NULL; > + =A0 =A0 =A0 =A0 =A0 =A0 rec->next =3D NULL; > + =A0 =A0 =A0 =A0 =A0 =A0 rec->type =3D record_end; > + =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_filtered (gdb_stdlog, _("\ > + =A0Reading record_end (one byte)\n")); > + =A0 =A0 =A0 =A0 =A0 =A0 record_arch_list_add (rec); > + =A0 =A0 =A0 =A0 =A0 =A0 insn_number ++; > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + > + =A0 =A0 =A0 =A0 =A0 default: > + =A0 =A0 =A0 =A0 =A0 =A0 error (_("Format of '%s' is not right."), args); > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 } > + =A0 =A0} > + > + =A0discard_cleanups (old_cleanups2); > + > + =A0/* Add record_arch_list_head to the end of record list. =A0(??? FIXM= E)*/ > + =A0for (rec =3D record_list; rec->next; rec =3D rec->next); > + =A0rec->next =3D record_arch_list_head; > + =A0record_arch_list_head->prev =3D rec; > + > + =A0/* Update record_insn_num and record_insn_max_num. =A0*/ > + =A0record_insn_num =3D insn_number; > + =A0if (record_insn_num > record_insn_max_num) > + =A0 =A0{ > + =A0 =A0 =A0record_insn_max_num =3D record_insn_num; > + =A0 =A0 =A0warning (_("Auto increase record/replay buffer limit to %d."= ), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_insn_max_num); > + =A0 =A0} > + > + =A0do_cleanups (old_cleanups); > + > + =A0/* Succeeded. =A0*/ > + =A0fprintf_filtered (gdb_stdout, "Loaded recfile %s.\n", args); > + =A0registers_changed (); > + =A0reinit_frame_cache (); > + =A0nullify_last_target_wait_ptid (); > + =A0print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); > +} > + > =A0/* Truncate the record log from the present point > =A0 =A0of replay until the end. =A0*/ > > @@ -1243,6 +1722,8 @@ info_record_command (char *args, int fro > =A0void > =A0_initialize_record (void) > =A0{ > + =A0struct cmd_list_element *c; > + > =A0 /* Init record_first. =A0*/ > =A0 record_first.prev =3D NULL; > =A0 record_first.next =3D NULL; > @@ -1276,6 +1757,15 @@ _initialize_record (void) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"info record ", 0, &infolist); > =A0 add_alias_cmd ("rec", "record", class_obscure, 1, &infolist); > > + =A0c =3D add_cmd ("dump", class_obscure, cmd_record_dump, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Dump the execution log to a file.\n\ > +Argument is optional filename. =A0Default filename is 'rec.'= ."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_cmdlist); > + =A0set_cmd_completer (c, filename_completer); > + =A0c =3D add_cmd ("load", class_obscure, cmd_record_load, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Load the execution log from a file. =A0Ar= gument is > filename."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_cmdlist); > + =A0set_cmd_completer (c, filename_completer); > > =A0 add_cmd ("delete", class_obscure, cmd_record_delete, > =A0 =A0 =A0 =A0 =A0 _("Delete the rest of execution log and start recordi= ng it > anew."), > @@ -1290,15 +1780,15 @@ _initialize_record (void) > > =A0 /* Record instructions number limit command. =A0*/ > =A0 add_setshow_boolean_cmd ("stop-at-limit", no_class, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_stop_at_lim= it, _("\ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&record_stop_at_limi= t, _("\ > =A0Set whether record/replay stops when record/replay buffer becomes full= ."), > _("\ > =A0Show whether record/replay stops when record/replay buffer becomes ful= l."), > _("\ > =A0Default is ON.\n\ > =A0When ON, if the record/replay buffer becomes full, ask user what to do= .\n\ > =A0When OFF, if the record/replay buffer becomes full,\n\ > =A0delete the oldest recorded instruction to make room for each new one."= ), > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, NULL, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&set_record_cmdl= ist, &show_record_cmdlist); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0NULL, NULL, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&set_record_cmdlist,= &show_record_cmdlist); > =A0 add_setshow_zinteger_cmd ("insn-number-max", no_class, > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&record_insn_max_n= um, > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Set record/repl= ay buffer limit."), > Index: linux-fork.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > 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 =A0 =A0 =A0 =A02 Jul 2009 22:24:07 -0000 =A0 =A0 =A0 1.29 > +++ linux-fork.c =A0 =A0 =A0 =A012 Aug 2009 22:28:43 -0000 > @@ -235,7 +235,6 @@ call_lseek (int fd, off_t offset, int wh > =A0static void > =A0fork_load_infrun_state (struct fork_info *fp) > =A0{ > - =A0extern void nullify_last_target_wait_ptid (); > =A0 int i; > > =A0 linux_nat_switch_fork (fp->ptid); > >