summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Snyder <msnyder@specifix.com>2005-12-01 02:11:01 +0000
committerMichael Snyder <msnyder@specifix.com>2005-12-01 02:11:01 +0000
commit8830a2bc66b4563204a3fd7f6f1c7e6258babf3b (patch)
tree8aee942d556144bf2b6ae22ce4b7bad260fc3bc3
parentd1a7185a2a5a66bc22970d13e8be41a174e8aaaa (diff)
downloadgdb-8830a2bc66b4563204a3fd7f6f1c7e6258babf3b.tar.gz
2005-11-30 Michael Snyder <msnyder@redhat.com>
* linux-fork.c (struct fork_info): Add fields for saving file offsets of all open file descriptors. (free_fork): Free storage for file offsets. (call_lseek): New function. Call lseek in the inferior. (fork_save_infrun_state): Use /proc and call_lseek to save file offsets for all open file descriptors in inferior. (fork_load_infrun_state): Use call_lseek to restore file offsets. (restart_command): Fix oversight, save fork id.
-rw-r--r--gdb/ChangeLog11
-rw-r--r--gdb/linux-fork.c76
2 files changed, 85 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 50ccc9f6aa0..b60a5df3b55 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,14 @@
+2005-11-30 Michael Snyder <msnyder@redhat.com>
+
+ * linux-fork.c (struct fork_info): Add fields for saving
+ file offsets of all open file descriptors.
+ (free_fork): Free storage for file offsets.
+ (call_lseek): New function. Call lseek in the inferior.
+ (fork_save_infrun_state): Use /proc and call_lseek to save
+ file offsets for all open file descriptors in inferior.
+ (fork_load_infrun_state): Use call_lseek to restore file offsets.
+ (restart_command): Fix oversight, save fork id.
+
2005-11-29 Michael Snyder <msnyder@redhat.com>
* linux-fork.c (process_command): New command, new function.
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index f9bd7a6dbbb..a922b562397 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -29,6 +29,9 @@
#include <sys/ptrace.h>
#include <sys/wait.h>
+#include <sys/param.h> /* For MAXPATHLEN */
+#include <dirent.h>
+#include <ctype.h>
struct fork_info *fork_list;
static int highest_fork_num;
@@ -48,6 +51,8 @@ struct fork_info
having to actually switch contexts. */
int clobber_regs; /* True if we should restore saved regs. */
int been_restarted; /* One time flag. */
+ off_t *filepos;
+ int maxfd;
};
/*
@@ -89,6 +94,8 @@ free_fork (struct fork_info *fp)
{
if (fp->savedregs)
regcache_xfree (fp->savedregs);
+ if (fp->filepos)
+ xfree (fp->filepos);
xfree (fp);
}
}
@@ -199,17 +206,41 @@ init_fork_list (void)
* Fork list <-> gdb interface:
*/
+/* call_lseek -- utility function for fork_load/fork_save.
+ Calls lseek in the (current) inferior process. */
+static off_t
+call_lseek (int fd, off_t offset, int whence)
+{
+ char exp[80];
+
+ snprintf (&exp[0], sizeof (exp), "lseek (%d, %ld, %d)",
+ fd, (long) offset, whence);
+ return (off_t) parse_and_eval_long (&exp[0]);
+}
+
/* Load infrun state for the fork PTID. */
static void
fork_load_infrun_state (struct fork_info *fp)
{
extern void nullify_last_target_wait_ptid ();
+ int i;
if (fp->savedregs && fp->clobber_regs)
regcache_cpy (current_regcache, fp->savedregs);
nullify_last_target_wait_ptid ();
+
+ /* Now restore the file positions of open file descriptors. */
+ if (fp->filepos)
+ {
+ for (i = 0; i <= fp->maxfd; i++)
+ if (fp->filepos[i] != (off_t) -1)
+ call_lseek (i, fp->filepos[i], SEEK_SET);
+ /* NOTE: I can get away with using SEEK_SET and SEEK_CUR because
+ this is native-only. If it ever has to be cross, we'll have
+ to rethink this. */
+ }
}
/* Save infrun state for the fork PTID.
@@ -219,11 +250,52 @@ fork_load_infrun_state (struct fork_info *fp)
extern void
fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
{
+ char path[MAXPATHLEN];
+ struct dirent *de;
+ DIR *d;
+
if (fp->savedregs)
regcache_xfree (fp->savedregs);
fp->savedregs = regcache_dup (current_regcache);
fp->clobber_regs = clobber_regs;
+
+ if (clobber_regs)
+ {
+ /* Now save the 'state' (file position) of all open file descriptors.
+ Unfortunately fork does not take care of that for us... */
+ snprintf (path, MAXPATHLEN, "/proc/%ld/fd", (long) PIDGET (fp->ptid));
+ if ((d = opendir (path)) != NULL)
+ {
+ long tmp;
+
+ fp->maxfd = 0;
+ while ((de = readdir (d)) != NULL)
+ {
+ /* Count open file descriptors (actually find highest
+ numbered). */
+ tmp = strtol (&de->d_name[0], NULL, 10);
+ if (fp->maxfd < tmp)
+ fp->maxfd = tmp;
+ }
+ /* Allocate array of file positions. */
+ fp->filepos = xrealloc (fp->filepos,
+ (fp->maxfd + 1) * sizeof (*fp->filepos));
+
+ /* Initialize to -1 (invalid). */
+ for (tmp = 0; tmp <= fp->maxfd; tmp++)
+ fp->filepos[tmp] = -1;
+
+ /* Now find actual file positions. */
+ rewinddir (d);
+ while ((de = readdir (d)) != NULL)
+ if (isdigit (de->d_name[0]))
+ {
+ tmp = strtol (&de->d_name[0], NULL, 10);
+ fp->filepos[tmp] = call_lseek (tmp, 0, SEEK_CUR);
+ }
+ }
+ }
}
/* linux_fork_killall. Let God sort 'em out... */
@@ -342,7 +414,7 @@ info_forks_command (char *arg, int from_tty)
printf_filtered (" ");
regcache_raw_read_unsigned (fp->savedregs, PC_REGNUM, &pc);
}
- printf_filtered ("%d %s", fp->num, target_tid_to_str (fp->ptid));
+ printf_filtered ("%d %s", fp->num, target_pid_to_str (fp->ptid));
if (fp->num == 0)
printf_filtered (" (main process)");
printf_filtered (" at ");
@@ -505,7 +577,7 @@ restart_command (char *args, int from_tty)
if (!args || !*args)
error ("Requires argument (checkpoint id, see info checkpoints)");
- if ((find_fork_id (parse_and_eval_long (args))) == NULL)
+ if ((fp = find_fork_id (parse_and_eval_long (args))) == NULL)
error ("Not found: checkpoint id %s", args);
linux_fork_context (fp, from_tty);