[Precord RFA/RFC] Check Linux sys_brk release memory in process record and replay.
Hui Zhu
teawater@gmail.com
Tue May 5 13:09:00 GMT 2009
Sorry I forget the patch.
On Tue, May 5, 2009 at 21:07, Hui Zhu <teawater@gmail.com> wrote:
> Hi guys,
>
> This patch will make linux-record can check if the sys_brk will
> release the memory or not. If memory will be released, gdb will query
> to user.
>
> For example:
> cat m.c
> #include <sys/types.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> #include <errno.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <stdint.h>
>
> int
> main(int argc,char *argv[],char *envp[])
> {
> sbrk (10);
> sbrk (-10);
>
> return (0);
> }
>
> gdb m
> GNU gdb (GDB) 6.8.50.20090505-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 "i686-pc-linux-gnu".
> For bug reporting instructions, please see:
> <http://www.gnu.org/software/gdb/bugs/>...
> (gdb) start
> Temporary breakpoint 1 at 0x8048385: file m.c, line 14.
> Starting program: /home/teawater/gdb/m
>
> Temporary breakpoint 1, main (argc=<value optimized out>, argv=<value
> optimized out>,
> envp=<value optimized out>) at m.c:14
> 14 sbrk (10);
> (gdb) record
> (gdb) n
> 15 sbrk (-10);
> (gdb)
> The next instruction is syscall brk. It will release the memory that
> will cause process record target get error. Do you want to stop the
> inferior?([y] or n)
> Process record: inferior program stopped.
>
> Program received signal SIGTRAP, Trace/breakpoint trap.
> 0xb7fe3405 in __kernel_vsyscall ()
>
>
> 2009-05-05 Hui Zhu <teawater@gmail.com>
>
> Add a architecture process record and replay reset interface
> and i386 and i386-linux record and replay reset functions.
>
> * gdbarch.sh (process_record_reset): This interface point to
> the function that reset the architecture process record and
> replay.
> * record.c (record_open): Call process_record_reset.
> * i386-tdep.c (i386_linux_record_reset): New function. Call
> tdep interface "i386_record_reset".
> (i386_gdbarch_init): Set "i386_linux_record_reset" to GDBARCH
> "process_record_reset" interface.
> * i386-tdep.h (gdbarch_tdep): New function pointer
> i386_record_reset that point to the function that can reset
> the process record.
> * i386-linux-tdep.c (i386_linux_record_reset): New function.
> Call record_linux_reset.
> (i386_linux_init_abi): Set "i386_linux_record_reset" to
> "i386_record_reset".
>
> Check Linux sys_brk release memory in process record
> and replay.
>
> * linux-record.c (record_top_of_heap): New variable.
> The current top of heap of inferior.
> (record_linux_reset): New function. The reset function of
> Linux process record and replay. It will reset the value
> of record_top_of_heap.
> (record_linux_system_call): Add the sys_brk check code.
> If this sys_brk will release the memory, query to user.
> * linux-record.h (record_linux_reset): New function extern.
>
>
> Thanks,
> Hui
>
-------------- next part --------------
---
gdbarch.c | 33 +++++++++++++++++
gdbarch.h | 8 ++++
gdbarch.sh | 3 +
i386-linux-tdep.c | 7 +++
i386-tdep.c | 8 ++++
i386-tdep.h | 2 +
linux-record.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
linux-record.h | 1
record.c | 4 ++
9 files changed, 167 insertions(+)
--- a/gdbarch.c
+++ b/gdbarch.c
@@ -240,6 +240,7 @@ struct gdbarch
gdbarch_static_transform_name_ftype *static_transform_name;
int sofun_address_maybe_missing;
gdbarch_process_record_ftype *process_record;
+ gdbarch_process_record_reset_ftype *process_record_reset;
gdbarch_target_signal_from_host_ftype *target_signal_from_host;
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
@@ -376,6 +377,7 @@ struct gdbarch startup_gdbarch =
0, /* static_transform_name */
0, /* sofun_address_maybe_missing */
0, /* process_record */
+ 0, /* process_record_reset */
default_target_signal_from_host, /* target_signal_from_host */
default_target_signal_to_host, /* target_signal_to_host */
0, /* get_siginfo_type */
@@ -633,6 +635,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of static_transform_name, has predicate */
/* Skip verify of sofun_address_maybe_missing, invalid_p == 0 */
/* Skip verify of process_record, has predicate */
+ /* Skip verify of process_record_reset, has predicate */
/* Skip verify of target_signal_from_host, invalid_p == 0 */
/* Skip verify of target_signal_to_host, invalid_p == 0 */
/* Skip verify of get_siginfo_type, has predicate */
@@ -955,6 +958,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
"gdbarch_dump: process_record = <%s>\n",
host_address_to_string (gdbarch->process_record));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_process_record_reset_p() = %d\n",
+ gdbarch_process_record_reset_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: process_record_reset = <%s>\n",
+ host_address_to_string (gdbarch->process_record_reset));
+ fprintf_unfiltered (file,
"gdbarch_dump: ps_regnum = %s\n",
plongest (gdbarch->ps_regnum));
fprintf_unfiltered (file,
@@ -3283,6 +3292,30 @@ set_gdbarch_process_record (struct gdbar
gdbarch->process_record = process_record;
}
+int
+gdbarch_process_record_reset_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->process_record_reset != NULL;
+}
+
+void
+gdbarch_process_record_reset (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->process_record_reset != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_process_record_reset called\n");
+ gdbarch->process_record_reset (gdbarch);
+}
+
+void
+set_gdbarch_process_record_reset (struct gdbarch *gdbarch,
+ gdbarch_process_record_reset_ftype process_record_reset)
+{
+ gdbarch->process_record_reset = process_record_reset;
+}
+
enum target_signal
gdbarch_target_signal_from_host (struct gdbarch *gdbarch, int signo)
{
--- a/gdbarch.h
+++ b/gdbarch.h
@@ -818,6 +818,14 @@ typedef int (gdbarch_process_record_ftyp
extern int gdbarch_process_record (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr);
extern void set_gdbarch_process_record (struct gdbarch *gdbarch, gdbarch_process_record_ftype *process_record);
+/* Reset the inside value of process record if need. */
+
+extern int gdbarch_process_record_reset_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_process_record_reset_ftype) (struct gdbarch *gdbarch);
+extern void gdbarch_process_record_reset (struct gdbarch *gdbarch);
+extern void set_gdbarch_process_record_reset (struct gdbarch *gdbarch, gdbarch_process_record_reset_ftype *process_record_reset);
+
/* Signal translation: translate inferior's signal (host's) number into
GDB's representation. */
--- a/gdbarch.sh
+++ b/gdbarch.sh
@@ -715,6 +715,9 @@ v:int:sofun_address_maybe_missing:::0:0:
# Return -1 if something goes wrong, 0 otherwise.
M:int:process_record:struct regcache *regcache, CORE_ADDR addr:regcache, addr
+# Reset the inside value of process record if need.
+M:void:process_record_reset:void
+
# Signal translation: translate inferior's signal (host's) number into
# GDB's representation.
m:enum target_signal:target_signal_from_host:int signo:signo::default_target_signal_from_host::0
--- a/i386-linux-tdep.c
+++ b/i386-linux-tdep.c
@@ -352,6 +352,12 @@ i386_linux_write_pc (struct regcache *re
regcache_cooked_write_unsigned (regcache, I386_LINUX_ORIG_EAX_REGNUM, -1);
}
+static void
+i386_linux_record_reset (struct gdbarch *gdbarch)
+{
+ record_linux_reset (gdbarch);
+}
+
/* Parse the arguments of current system call instruction and record
the values of the registers and memory that will be changed into
"record_arch_list". This instruction is "int 0x80" (Linux
@@ -787,6 +793,7 @@ i386_linux_init_abi (struct gdbarch_info
i386_linux_record_tdep.arg4 = I386_ESI_REGNUM;
i386_linux_record_tdep.arg5 = I386_EDI_REGNUM;
+ tdep->i386_record_reset = i386_linux_record_reset;
tdep->i386_intx80_record = i386_linux_intx80_sysenter_record;
tdep->i386_sysenter_record = i386_linux_intx80_sysenter_record;
--- a/i386-tdep.c
+++ b/i386-tdep.c
@@ -5086,6 +5086,13 @@ no_support:
return -1;
}
+static void
+i386_process_record_reset (struct gdbarch *gdbarch)
+{
+ if (gdbarch_tdep (gdbarch)->i386_record_reset)
+ gdbarch_tdep (gdbarch)->i386_record_reset (gdbarch);
+}
+
static struct gdbarch *
i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
@@ -5278,6 +5285,7 @@ i386_gdbarch_init (struct gdbarch_info i
i386_skip_permanent_breakpoint);
set_gdbarch_process_record (gdbarch, i386_process_record);
+ set_gdbarch_process_record_reset (gdbarch, i386_process_record_reset);
return gdbarch;
}
--- a/i386-tdep.h
+++ b/i386-tdep.h
@@ -108,6 +108,8 @@ struct gdbarch_tdep
struct type *i386_sse_type;
/* Process record/replay target. */
+ /* Reset */
+ void (*i386_record_reset) (struct gdbarch *gdbarch);
/* Parse intx80 args. */
int (*i386_intx80_record) (struct regcache *regcache);
/* Parse sysenter args. */
--- a/linux-record.c
+++ b/linux-record.c
@@ -20,6 +20,12 @@
#include "defs.h"
#include "target.h"
#include "regcache.h"
+#include "infcall.h"
+#include "objfiles.h"
+#include "value.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "gdbthread.h"
#include "record.h"
#include "linux-record.h"
@@ -80,6 +86,56 @@
#define RECORD_Q_XGETQSTAT (('5' << 8) + 5)
#define RECORD_Q_XGETQUOTA (('3' << 8) + 3)
+/* record_top_of_heap is the current top of heap of inferior.
+ When record deal with sys_brk, it will be used.
+ Get it need call call_function_by_hand, this function will reset a lot
+ of status of inferior. It will make process record get error
+ if call it in record_linux_system_call. So get record_top_of_heap in
+ record_linux_reset. */
+
+static bfd_vma record_top_of_heap;
+
+void
+record_linux_reset (struct gdbarch *gdbarch)
+{
+ struct value *sbrk_fn;
+ struct objfile *sbrk_objf;
+
+ record_top_of_heap = 0;
+
+ /* Get sbrk_fn and zero. Because all of them
+ will be free by free_all_values in each command begin. */
+ sbrk_fn = NULL;
+ if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL)
+ sbrk_fn = find_function_in_inferior ("sbrk", &sbrk_objf);
+ if (!sbrk_fn)
+ {
+ if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL)
+ sbrk_fn = find_function_in_inferior ("_sbrk", &sbrk_objf);
+ }
+
+ if (sbrk_fn)
+ {
+ struct value *ret;
+ struct value *zero = value_from_longest
+ (builtin_type (get_objfile_arch (sbrk_objf))->builtin_int, 0);
+
+ remove_breakpoints ();
+ ret = call_function_by_hand (sbrk_fn, 1, &zero);
+ insert_breakpoints ();
+
+ if (ret)
+ {
+ record_top_of_heap = value_as_long (ret);
+ }
+ }
+
+ if (!record_top_of_heap)
+ fprintf_unfiltered (gdb_stdlog,
+ _("Process record get current "
+ "top of heap failied.\n"));
+}
+
/* When the architecture process record get a Linux syscall
instruction, it will get a Linux syscall number of this
architecture and convert it to the Linux syscall number "num" which
@@ -246,8 +302,53 @@ record_linux_system_call (int num, struc
/* sys_ni_syscall */
case 44:
+ break;
+
/* sys_brk */
case 45:
+ {
+ int q;
+ bfd_vma end_data_segment;
+
+ regcache_raw_read (regcache, tdep->arg1,
+ (gdb_byte *) & end_data_segment);
+
+ if (record_top_of_heap)
+ {
+ if (end_data_segment && record_top_of_heap > end_data_segment)
+ {
+ target_terminal_ours ();
+ q =
+ yquery (_("The next instruction is syscall brk. "
+ "It will release the memory that will cause "
+ "process record target get error. Do "
+ "you want to stop the inferior?"));
+ target_terminal_inferior ();
+ if (q)
+ return 1;
+ }
+ }
+ else
+ {
+
+ target_terminal_ours ();
+ q =
+ yquery (_("The next instruction is syscall brk. "
+ "Process record cannot make sure it will "
+ "release memory or not. "
+ "It may cause process record target get error. "
+ "Do you want to stop the inferior?"));
+ target_terminal_inferior ();
+ if (q)
+ return 1;
+ }
+
+ /* If syscall brk execute, end_data_segment will be
+ the top of heap. */
+ record_top_of_heap = end_data_segment;
+ }
+ break;
+
/* sys_setgid16 */
case 46:
/* sys_getgid16 */
--- a/linux-record.h
+++ b/linux-record.h
@@ -167,6 +167,7 @@ struct linux_record_tdep
int arg5;
};
+extern void record_linux_reset (struct gdbarch *gdbarch);
extern int record_linux_system_call (int num, struct regcache *regcache,
struct linux_record_tdep *tdep);
--- a/record.c
+++ b/record.c
@@ -440,6 +440,10 @@ record_open (char *name, int from_tty)
return;
}
+ /*Reset the gdbarch part of process record. */
+ if (gdbarch_process_record_reset_p (current_gdbarch))
+ gdbarch_process_record_reset (current_gdbarch);
+
/*Reset the beneath function pointers. */
record_beneath_to_resume = NULL;
record_beneath_to_wait = NULL;
More information about the Gdb-patches
mailing list