Fix leaks in all the linux osdata annex transfers + code factorization.
authorPhilippe Waroquiers <philippe.waroquiers@skynet.be>
Sat, 8 Dec 2018 16:28:31 +0000 (17:28 +0100)
committerPhilippe Waroquiers <philippe.waroquiers@skynet.be>
Tue, 11 Dec 2018 22:00:47 +0000 (23:00 +0100)
Valgrind reports leaks in all linux osdata annex transfers of linux-osdata.c.

A typical leak (this one is of gdb.base/info-os) is:
==10592== VALGRIND_GDB_ERROR_BEGIN
==10592== 65,536 bytes in 1 blocks are definitely lost in loss record 3,175 of 3,208
==10592==    at 0x4C2E273: realloc (vg_replace_malloc.c:826)
==10592==    by 0x409B0C: xrealloc (common-utils.c:62)
==10592==    by 0x408BC3: buffer_grow(buffer*, char const*, unsigned long) [clone .part.1] (buffer.c:40)
==10592==    by 0x5263DF: linux_xfer_osdata_processes(unsigned char*, unsigned long, unsigned long) (linux-osdata.c:370)
==10592==    by 0x520875: linux_nat_xfer_osdata (linux-nat.c:4214)
...

The leaks are created because the linux_xfer_osdata_* functions
transfer the ownership of their 'static struct buffer' memory
to their 'static char *buf' local var, but then call buffer_free
instead of xfree-ing buf.

I see no reason why the ownership of the memory has to be transferred
from a local var to another local var, so the fix consists in dropping
the 'static char *buf' and accessing the struct buffer memory where needed.

Also, because this bug was replicated in all functions, and there was
a non neglectible amount of duplicated code, the setup and usage
of the 'static struct buffer' is factorized in a new function
common_getter.  The buffer for a specific annex is now a member
of the struct osdata_type instead of being a static var of each
linux_xfer_osdata_* function.

Thanks to this, all the linux_xfer_osdata_* do not have
anymore any logic related to the partial transfer of data: they now
only build the xml data in a struct buffer.
This all removes about 300 SLOC.

Note: git diff/git format-patch shows a lot of differences only due
to space changes/indentation changes.
So, git diff -w helps to look only at the relevant differences.

gdb/ChangeLog
2018-12-11  Philippe Waroquiers  <philippe.waroquiers@skynet.be>

* nat/linux-osdata.c (common_getter): New function.
(struct osdata_type): Change getter to take_snapshot.
Add LONGEST len_avail and struct buffer buffer.
Change all elements in the initializer.
Add an element for the list of types.
(linux_xfer_osdata_info_os_types): New function.
(linux_common_xfer_osdata): Use common_getter for the list of types.
Replace getter call by common_getter.
(linux_xfer_osdata_cpus): Remove args READBUF, OFFSET, LEN.
Add arg BUFFER.  Only keep the code that adds data in BUFFER.
(linux_xfer_osdata_fds): Likewise.
(linux_xfer_osdata_modules): Likewise.
(linux_xfer_osdata_msg): Likewise.
(linux_xfer_osdata_processes): Likewise.
(linux_xfer_osdata_processgroups): Likewise.
(linux_xfer_osdata_sem): Likewise.
(linux_xfer_osdata_shm): Likewise.
(linux_xfer_osdata_isockets): Likewise.
(linux_xfer_osdata_threads): Likewise.

gdb/ChangeLog
gdb/nat/linux-osdata.c

index 04904c6..3d35d3b 100644 (file)
@@ -1,5 +1,27 @@
 2018-12-11  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
 
+       * nat/linux-osdata.c (common_getter): New function.
+       (struct osdata_type): Change getter to take_snapshot.
+       Add LONGEST len_avail and struct buffer buffer.
+       Change all elements in the initializer.
+       Add an element for the list of types.
+       (linux_xfer_osdata_info_os_types): New function.
+       (linux_common_xfer_osdata): Use common_getter for the list of types.
+       Replace getter call by common_getter.
+       (linux_xfer_osdata_cpus): Remove args READBUF, OFFSET, LEN.
+       Add arg BUFFER.  Only keep the code that adds data in BUFFER.
+       (linux_xfer_osdata_fds): Likewise.
+       (linux_xfer_osdata_modules): Likewise.
+       (linux_xfer_osdata_msg): Likewise.
+       (linux_xfer_osdata_processes): Likewise.
+       (linux_xfer_osdata_processgroups): Likewise.
+       (linux_xfer_osdata_sem): Likewise.
+       (linux_xfer_osdata_shm): Likewise.
+       (linux_xfer_osdata_isockets): Likewise.
+       (linux_xfer_osdata_threads): Likewise.
+
+2018-12-11  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
+
        * nat/linux-osdata.c: Removed various trailing spaces.
 
 2018-12-10  Andrew Burgess  <andrew.burgess@embecosm.com>
index 62ab42d..baca7fe 100644 (file)
@@ -278,114 +278,83 @@ get_cores_used_by_process (PID_T pid, int *cores, const int num_cores)
   return task_count;
 }
 
-static LONGEST
-linux_xfer_osdata_processes (gdb_byte *readbuf,
-                            ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_processes (struct buffer *buffer)
 {
-  /* We make the process list snapshot when the object starts to be read.  */
-  static const char *buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  DIR *dirp;
 
-  if (offset == 0)
-    {
-      DIR *dirp;
+  buffer_grow_str (buffer, "<osdata type=\"processes\">\n");
 
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"processes\">\n");
+  dirp = opendir ("/proc");
+  if (dirp)
+    {
+      const int num_cores = sysconf (_SC_NPROCESSORS_ONLN);
+      struct dirent *dp;
 
-      dirp = opendir ("/proc");
-      if (dirp)
+      while ((dp = readdir (dirp)) != NULL)
        {
-         const int num_cores = sysconf (_SC_NPROCESSORS_ONLN);
-         struct dirent *dp;
-
-         while ((dp = readdir (dirp)) != NULL)
-           {
-             PID_T pid;
-             uid_t owner;
-             char user[UT_NAMESIZE];
-             char *command_line;
-             int *cores;
-             int task_count;
-             char *cores_str;
-             int i;
-
-             if (!isdigit (dp->d_name[0])
-                 || NAMELEN (dp) > MAX_PID_T_STRLEN)
-               continue;
+         PID_T pid;
+         uid_t owner;
+         char user[UT_NAMESIZE];
+         char *command_line;
+         int *cores;
+         int task_count;
+         char *cores_str;
+         int i;
 
-             sscanf (dp->d_name, "%lld", &pid);
-             command_line = commandline_from_pid (pid);
-
-             if (get_process_owner (&owner, pid) == 0)
-               user_from_uid (user, sizeof (user), owner);
-             else
-               strcpy (user, "?");
-
-             /* Find CPU cores used by the process.  */
-             cores = XCNEWVEC (int, num_cores);
-             task_count = get_cores_used_by_process (pid, cores, num_cores);
-             cores_str = (char *) xcalloc (task_count, sizeof ("4294967295") + 1);
-
-             for (i = 0; i < num_cores && task_count > 0; ++i)
-               if (cores[i])
-                 {
-                   char core_str[sizeof ("4294967295")];
-
-                   sprintf (core_str, "%d", i);
-                   strcat (cores_str, core_str);
-
-                   task_count -= cores[i];
-                   if (task_count > 0)
-                     strcat (cores_str, ",");
-                 }
-
-             xfree (cores);
-
-             buffer_xml_printf (
-                 &buffer,
-                 "<item>"
-                 "<column name=\"pid\">%lld</column>"
-                 "<column name=\"user\">%s</column>"
-                 "<column name=\"command\">%s</column>"
-                 "<column name=\"cores\">%s</column>"
-                 "</item>",
-                 pid,
-                 user,
-                 command_line ? command_line : "",
-                 cores_str);
-
-             xfree (command_line);
-             xfree (cores_str);
-           }
+         if (!isdigit (dp->d_name[0])
+             || NAMELEN (dp) > MAX_PID_T_STRLEN)
+           continue;
 
-         closedir (dirp);
+         sscanf (dp->d_name, "%lld", &pid);
+         command_line = commandline_from_pid (pid);
+
+         if (get_process_owner (&owner, pid) == 0)
+           user_from_uid (user, sizeof (user), owner);
+         else
+           strcpy (user, "?");
+
+         /* Find CPU cores used by the process.  */
+         cores = XCNEWVEC (int, num_cores);
+         task_count = get_cores_used_by_process (pid, cores, num_cores);
+         cores_str = (char *) xcalloc (task_count, sizeof ("4294967295") + 1);
+
+         for (i = 0; i < num_cores && task_count > 0; ++i)
+           if (cores[i])
+             {
+               char core_str[sizeof ("4294967295")];
+
+               sprintf (core_str, "%d", i);
+               strcat (cores_str, core_str);
+
+               task_count -= cores[i];
+               if (task_count > 0)
+                 strcat (cores_str, ",");
+             }
+
+         xfree (cores);
+
+         buffer_xml_printf
+           (buffer,
+            "<item>"
+            "<column name=\"pid\">%lld</column>"
+            "<column name=\"user\">%s</column>"
+            "<column name=\"command\">%s</column>"
+            "<column name=\"cores\">%s</column>"
+            "</item>",
+            pid,
+            user,
+            command_line ? command_line : "",
+            cores_str);
+
+         xfree (command_line);
+         xfree (cores_str);
        }
 
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      buf = buffer_finish (&buffer);
-      len_avail = strlen (buf);
-    }
-
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      buf = NULL;
-      len_avail = 0;
-      return 0;
+      closedir (dirp);
     }
 
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
 /* A simple PID/PGID pair.  */
@@ -425,428 +394,305 @@ struct pid_pgid_entry
   PID_T pid, pgid;
 };
 
-/* Collect all process groups from /proc.  */
+/* Collect all process groups from /proc in BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_processgroups (gdb_byte *readbuf,
-                                ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_processgroups (struct buffer *buffer)
 {
-  /* We make the process list snapshot when the object starts to be read.  */
-  static const char *buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  DIR *dirp;
 
-  if (offset == 0)
+  buffer_grow_str (buffer, "<osdata type=\"process groups\">\n");
+
+  dirp = opendir ("/proc");
+  if (dirp)
     {
-      DIR *dirp;
+      std::vector<pid_pgid_entry> process_list;
+      struct dirent *dp;
 
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"process groups\">\n");
+      process_list.reserve (512);
 
-      dirp = opendir ("/proc");
-      if (dirp)
+      /* Build list consisting of PIDs followed by their
+        associated PGID.  */
+      while ((dp = readdir (dirp)) != NULL)
        {
-         std::vector<pid_pgid_entry> process_list;
-         struct dirent *dp;
-
-         process_list.reserve (512);
+         PID_T pid, pgid;
 
-         /* Build list consisting of PIDs followed by their
-            associated PGID.  */
-         while ((dp = readdir (dirp)) != NULL)
-           {
-             PID_T pid, pgid;
-
-             if (!isdigit (dp->d_name[0])
-                 || NAMELEN (dp) > MAX_PID_T_STRLEN)
-               continue;
+         if (!isdigit (dp->d_name[0])
+             || NAMELEN (dp) > MAX_PID_T_STRLEN)
+           continue;
 
-             sscanf (dp->d_name, "%lld", &pid);
-             pgid = getpgid (pid);
+         sscanf (dp->d_name, "%lld", &pid);
+         pgid = getpgid (pid);
 
-             if (pgid > 0)
-               process_list.emplace_back (pid, pgid);
-           }
+         if (pgid > 0)
+           process_list.emplace_back (pid, pgid);
+       }
 
-         closedir (dirp);
+      closedir (dirp);
 
-         /* Sort the process list.  */
-         std::sort (process_list.begin (), process_list.end ());
+      /* Sort the process list.  */
+      std::sort (process_list.begin (), process_list.end ());
 
-         for (const pid_pgid_entry &entry : process_list)
-           {
-             PID_T pid = entry.pid;
-             PID_T pgid = entry.pgid;
-             char leader_command[32];
-             char *command_line;
-
-             command_from_pid (leader_command, sizeof (leader_command), pgid);
-             command_line = commandline_from_pid (pid);
-
-             buffer_xml_printf (
-                 &buffer,
-                 "<item>"
-                 "<column name=\"pgid\">%lld</column>"
-                 "<column name=\"leader command\">%s</column>"
-                 "<column name=\"pid\">%lld</column>"
-                 "<column name=\"command line\">%s</column>"
-                 "</item>",
-                 pgid,
-                 leader_command,
-                 pid,
-                 command_line ? command_line : "");
-
-             xfree (command_line);
-           }
+      for (const pid_pgid_entry &entry : process_list)
+       {
+         PID_T pid = entry.pid;
+         PID_T pgid = entry.pgid;
+         char leader_command[32];
+         char *command_line;
+
+         command_from_pid (leader_command, sizeof (leader_command), pgid);
+         command_line = commandline_from_pid (pid);
+
+         buffer_xml_printf
+           (buffer,
+            "<item>"
+            "<column name=\"pgid\">%lld</column>"
+            "<column name=\"leader command\">%s</column>"
+            "<column name=\"pid\">%lld</column>"
+            "<column name=\"command line\">%s</column>"
+            "</item>",
+            pgid,
+            leader_command,
+            pid,
+            command_line ? command_line : "");
+
+         xfree (command_line);
        }
-
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      buf = buffer_finish (&buffer);
-      len_avail = strlen (buf);
-    }
-
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      buf = NULL;
-      len_avail = 0;
-      return 0;
     }
 
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
 /* Collect all the threads in /proc by iterating through processes and
-   then tasks within each process.  */
+   then tasks within each process in BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_threads (gdb_byte *readbuf,
-                          ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_threads (struct buffer *buffer)
 {
-  /* We make the process list snapshot when the object starts to be read.  */
-  static const char *buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  DIR *dirp;
 
-  if (offset == 0)
-    {
-      DIR *dirp;
+  buffer_grow_str (buffer, "<osdata type=\"threads\">\n");
 
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"threads\">\n");
+  dirp = opendir ("/proc");
+  if (dirp)
+    {
+      struct dirent *dp;
 
-      dirp = opendir ("/proc");
-      if (dirp)
+      while ((dp = readdir (dirp)) != NULL)
        {
-         struct dirent *dp;
+         struct stat statbuf;
+         char procentry[sizeof ("/proc/4294967295")];
 
-         while ((dp = readdir (dirp)) != NULL)
-           {
-             struct stat statbuf;
-             char procentry[sizeof ("/proc/4294967295")];
+         if (!isdigit (dp->d_name[0])
+             || NAMELEN (dp) > sizeof ("4294967295") - 1)
+           continue;
 
-             if (!isdigit (dp->d_name[0])
-                 || NAMELEN (dp) > sizeof ("4294967295") - 1)
-               continue;
+         xsnprintf (procentry, sizeof (procentry), "/proc/%s",
+                    dp->d_name);
+         if (stat (procentry, &statbuf) == 0
+             && S_ISDIR (statbuf.st_mode))
+           {
+             DIR *dirp2;
+             PID_T pid;
+             char command[32];
 
-             xsnprintf (procentry, sizeof (procentry), "/proc/%s",
-                        dp->d_name);
-             if (stat (procentry, &statbuf) == 0
-                 && S_ISDIR (statbuf.st_mode))
-               {
-                 DIR *dirp2;
-                 PID_T pid;
-                 char command[32];
+             std::string pathname
+               = string_printf ("/proc/%s/task", dp->d_name);
 
-                 std::string pathname
-                   = string_printf ("/proc/%s/task", dp->d_name);
+             pid = atoi (dp->d_name);
+             command_from_pid (command, sizeof (command), pid);
 
-                 pid = atoi (dp->d_name);
-                 command_from_pid (command, sizeof (command), pid);
+             dirp2 = opendir (pathname.c_str ());
 
-                 dirp2 = opendir (pathname.c_str ());
+             if (dirp2)
+               {
+                 struct dirent *dp2;
 
-                 if (dirp2)
+                 while ((dp2 = readdir (dirp2)) != NULL)
                    {
-                     struct dirent *dp2;
-
-                     while ((dp2 = readdir (dirp2)) != NULL)
-                       {
-                         PID_T tid;
-                         int core;
-
-                         if (!isdigit (dp2->d_name[0])
-                             || NAMELEN (dp2) > sizeof ("4294967295") - 1)
-                           continue;
-
-                         tid = atoi (dp2->d_name);
-                         core = linux_common_core_of_thread (ptid_t (pid, tid, 0));
-
-                         buffer_xml_printf (
-                           &buffer,
-                           "<item>"
-                           "<column name=\"pid\">%lld</column>"
-                           "<column name=\"command\">%s</column>"
-                           "<column name=\"tid\">%lld</column>"
-                           "<column name=\"core\">%d</column>"
-                           "</item>",
-                           pid,
-                           command,
-                           tid,
-                           core);
-                       }
-
-                     closedir (dirp2);
+                     PID_T tid;
+                     int core;
+
+                     if (!isdigit (dp2->d_name[0])
+                         || NAMELEN (dp2) > sizeof ("4294967295") - 1)
+                       continue;
+
+                     tid = atoi (dp2->d_name);
+                     core = linux_common_core_of_thread (ptid_t (pid, tid, 0));
+
+                     buffer_xml_printf
+                       (buffer,
+                        "<item>"
+                        "<column name=\"pid\">%lld</column>"
+                        "<column name=\"command\">%s</column>"
+                        "<column name=\"tid\">%lld</column>"
+                        "<column name=\"core\">%d</column>"
+                        "</item>",
+                        pid,
+                        command,
+                        tid,
+                        core);
                    }
+
+                 closedir (dirp2);
                }
            }
-
-         closedir (dirp);
        }
 
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      buf = buffer_finish (&buffer);
-      len_avail = strlen (buf);
+      closedir (dirp);
     }
 
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      buf = NULL;
-      len_avail = 0;
-      return 0;
-    }
-
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
-/* Collect data about the cpus/cores on the system */
+/* Collect data about the cpus/cores on the system in BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_cpus (gdb_byte *readbuf,
-                          ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_cpus (struct buffer *buffer)
 {
-  static const char *saved_buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  int first_item = 1;
 
-  if (offset == 0)
-    {
-      int first_item = 1;
+  buffer_grow_str (buffer, "<osdata type=\"cpus\">\n");
 
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      saved_buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"cpus\">\n");
+  gdb_file_up fp = gdb_fopen_cloexec ("/proc/cpuinfo", "r");
+  if (fp != NULL)
+    {
+      char buf[8192];
 
-      gdb_file_up fp = gdb_fopen_cloexec ("/proc/cpuinfo", "r");
-      if (fp != NULL)
+      do
        {
-         char buf[8192];
-
-         do
+         if (fgets (buf, sizeof (buf), fp.get ()))
            {
-             if (fgets (buf, sizeof (buf), fp.get ()))
-               {
-                 char *key, *value;
-                 int i = 0;
+             char *key, *value;
+             int i = 0;
 
-                 key = strtok (buf, ":");
-                 if (key == NULL)
-                   continue;
-
-                 value = strtok (NULL, ":");
-                 if (value == NULL)
-                   continue;
+             key = strtok (buf, ":");
+             if (key == NULL)
+               continue;
 
-                 while (key[i] != '\t' && key[i] != '\0')
-                   i++;
+             value = strtok (NULL, ":");
+             if (value == NULL)
+               continue;
 
-                 key[i] = '\0';
+             while (key[i] != '\t' && key[i] != '\0')
+               i++;
 
-                 i = 0;
-                 while (value[i] != '\t' && value[i] != '\0')
-                   i++;
+             key[i] = '\0';
 
-                 value[i] = '\0';
+             i = 0;
+             while (value[i] != '\t' && value[i] != '\0')
+               i++;
 
-                 if (strcmp (key, "processor") == 0)
-                   {
-                     if (first_item)
-                       buffer_grow_str (&buffer, "<item>");
-                     else
-                       buffer_grow_str (&buffer, "</item><item>");
+             value[i] = '\0';
 
-                     first_item = 0;
-                   }
+             if (strcmp (key, "processor") == 0)
+               {
+                 if (first_item)
+                   buffer_grow_str (buffer, "<item>");
+                 else
+                   buffer_grow_str (buffer, "</item><item>");
 
-                 buffer_xml_printf (&buffer,
-                                    "<column name=\"%s\">%s</column>",
-                                    key,
-                                    value);
+                 first_item = 0;
                }
-           }
-         while (!feof (fp.get ()));
 
-         if (first_item == 0)
-           buffer_grow_str (&buffer, "</item>");
+             buffer_xml_printf (buffer,
+                                "<column name=\"%s\">%s</column>",
+                                key,
+                                value);
+           }
        }
+      while (!feof (fp.get ()));
 
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      saved_buf = buffer_finish (&buffer);
-      len_avail = strlen (saved_buf);
-    }
-
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      saved_buf = NULL;
-      len_avail = 0;
-      return 0;
+      if (first_item == 0)
+       buffer_grow_str (buffer, "</item>");
     }
 
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, saved_buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
 /* Collect all the open file descriptors found in /proc and put the details
-   found about them into READBUF.  */
+   found about them into BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_fds (gdb_byte *readbuf,
-                      ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_fds (struct buffer *buffer)
 {
-  /* We make the process list snapshot when the object starts to be read.  */
-  static const char *saved_buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  DIR *dirp;
 
-  if (offset == 0)
-    {
-      DIR *dirp;
+  buffer_grow_str (buffer, "<osdata type=\"files\">\n");
 
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      saved_buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"files\">\n");
+  dirp = opendir ("/proc");
+  if (dirp)
+    {
+      struct dirent *dp;
 
-      dirp = opendir ("/proc");
-      if (dirp)
+      while ((dp = readdir (dirp)) != NULL)
        {
-         struct dirent *dp;
+         struct stat statbuf;
+         char procentry[sizeof ("/proc/4294967295")];
 
-         while ((dp = readdir (dirp)) != NULL)
-           {
-             struct stat statbuf;
-             char procentry[sizeof ("/proc/4294967295")];
+         if (!isdigit (dp->d_name[0])
+             || NAMELEN (dp) > sizeof ("4294967295") - 1)
+           continue;
 
-             if (!isdigit (dp->d_name[0])
-                 || NAMELEN (dp) > sizeof ("4294967295") - 1)
-               continue;
+         xsnprintf (procentry, sizeof (procentry), "/proc/%s",
+                    dp->d_name);
+         if (stat (procentry, &statbuf) == 0
+             && S_ISDIR (statbuf.st_mode))
+           {
+             DIR *dirp2;
+             PID_T pid;
+             char command[32];
 
-             xsnprintf (procentry, sizeof (procentry), "/proc/%s",
-                        dp->d_name);
-             if (stat (procentry, &statbuf) == 0
-                 && S_ISDIR (statbuf.st_mode))
-               {
-                 DIR *dirp2;
-                 PID_T pid;
-                 char command[32];
+             pid = atoi (dp->d_name);
+             command_from_pid (command, sizeof (command), pid);
 
-                 pid = atoi (dp->d_name);
-                 command_from_pid (command, sizeof (command), pid);
+             std::string pathname
+               = string_printf ("/proc/%s/fd", dp->d_name);
+             dirp2 = opendir (pathname.c_str ());
 
-                 std::string pathname
-                   = string_printf ("/proc/%s/fd", dp->d_name);
-                 dirp2 = opendir (pathname.c_str ());
+             if (dirp2)
+               {
+                 struct dirent *dp2;
 
-                 if (dirp2)
+                 while ((dp2 = readdir (dirp2)) != NULL)
                    {
-                     struct dirent *dp2;
-
-                     while ((dp2 = readdir (dirp2)) != NULL)
-                       {
-                         char buf[1000];
-                         ssize_t rslt;
-
-                         if (!isdigit (dp2->d_name[0]))
-                           continue;
-
-                         std::string fdname
-                           = string_printf ("%s/%s", pathname.c_str (),
-                                            dp2->d_name);
-                         rslt = readlink (fdname.c_str (), buf,
-                                          sizeof (buf) - 1);
-                         if (rslt >= 0)
-                           buf[rslt] = '\0';
-
-                         buffer_xml_printf (
-                           &buffer,
-                           "<item>"
-                           "<column name=\"pid\">%s</column>"
-                           "<column name=\"command\">%s</column>"
-                           "<column name=\"file descriptor\">%s</column>"
-                           "<column name=\"name\">%s</column>"
-                           "</item>",
-                           dp->d_name,
-                           command,
-                           dp2->d_name,
-                           (rslt >= 0 ? buf : dp2->d_name));
-                       }
-
-                     closedir (dirp2);
+                     char buf[1000];
+                     ssize_t rslt;
+
+                     if (!isdigit (dp2->d_name[0]))
+                       continue;
+
+                     std::string fdname
+                       = string_printf ("%s/%s", pathname.c_str (),
+                                        dp2->d_name);
+                     rslt = readlink (fdname.c_str (), buf,
+                                      sizeof (buf) - 1);
+                     if (rslt >= 0)
+                       buf[rslt] = '\0';
+
+                     buffer_xml_printf
+                       (buffer,
+                        "<item>"
+                        "<column name=\"pid\">%s</column>"
+                        "<column name=\"command\">%s</column>"
+                        "<column name=\"file descriptor\">%s</column>"
+                        "<column name=\"name\">%s</column>"
+                        "</item>",
+                        dp->d_name,
+                        command,
+                        dp2->d_name,
+                        (rslt >= 0 ? buf : dp2->d_name));
                    }
+
+                 closedir (dirp2);
                }
            }
-
-         closedir (dirp);
        }
 
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      saved_buf = buffer_finish (&buffer);
-      len_avail = strlen (saved_buf);
+      closedir (dirp);
     }
 
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      saved_buf = NULL;
-      len_avail = 0;
-      return 0;
-    }
-
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, saved_buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
 /* Returns the socket state STATE in textual form.  */
@@ -1039,49 +885,19 @@ print_sockets (unsigned short family, int tcp, struct buffer *buffer)
     }
 }
 
-/* Collect data about internet sockets and write it into READBUF.  */
+/* Collect data about internet sockets and write it into BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_isockets (gdb_byte *readbuf,
-                           ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_isockets (struct buffer *buffer)
 {
-  static const char *buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
-
-  if (offset == 0)
-    {
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"I sockets\">\n");
-
-      print_sockets (AF_INET, 1, &buffer);
-      print_sockets (AF_INET, 0, &buffer);
-      print_sockets (AF_INET6, 1, &buffer);
-      print_sockets (AF_INET6, 0, &buffer);
-
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      buf = buffer_finish (&buffer);
-      len_avail = strlen (buf);
-    }
+  buffer_grow_str (buffer, "<osdata type=\"I sockets\">\n");
 
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      buf = NULL;
-      len_avail = 0;
-      return 0;
-    }
+  print_sockets (AF_INET, 1, buffer);
+  print_sockets (AF_INET, 0, buffer);
+  print_sockets (AF_INET6, 1, buffer);
+  print_sockets (AF_INET6, 0, buffer);
 
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
 /* Converts the time SECONDS into textual form and copies it into a
@@ -1120,546 +936,444 @@ group_from_gid (char *group, int maxlen, gid_t gid)
 }
 
 /* Collect data about shared memory recorded in /proc and write it
-   into READBUF.  */
+   into BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_shm (gdb_byte *readbuf,
-                      ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_shm (struct buffer *buffer)
 {
-  static const char *saved_buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  buffer_grow_str (buffer, "<osdata type=\"shared memory\">\n");
 
-  if (offset == 0)
+  gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
+  if (fp)
     {
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      saved_buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"shared memory\">\n");
-
-      gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
-      if (fp)
-       {
-         char buf[8192];
+      char buf[8192];
 
-         do
+      do
+       {
+         if (fgets (buf, sizeof (buf), fp.get ()))
            {
-             if (fgets (buf, sizeof (buf), fp.get ()))
+             key_t key;
+             uid_t uid, cuid;
+             gid_t gid, cgid;
+             PID_T cpid, lpid;
+             int shmid, size, nattch;
+             TIME_T atime, dtime, ctime;
+             unsigned int perms;
+             int items_read;
+
+             items_read = sscanf (buf,
+                                  "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
+                                  &key, &shmid, &perms, &size,
+                                  &cpid, &lpid,
+                                  &nattch,
+                                  &uid, &gid, &cuid, &cgid,
+                                  &atime, &dtime, &ctime);
+
+             if (items_read == 14)
                {
-                 key_t key;
-                 uid_t uid, cuid;
-                 gid_t gid, cgid;
-                 PID_T cpid, lpid;
-                 int shmid, size, nattch;
-                 TIME_T atime, dtime, ctime;
-                 unsigned int perms;
-                 int items_read;
-
-                 items_read = sscanf (buf,
-                                      "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
-                                      &key, &shmid, &perms, &size,
-                                      &cpid, &lpid,
-                                      &nattch,
-                                      &uid, &gid, &cuid, &cgid,
-                                      &atime, &dtime, &ctime);
-
-                 if (items_read == 14)
-                   {
-                     char user[UT_NAMESIZE], group[UT_NAMESIZE];
-                     char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
-                     char ccmd[32], lcmd[32];
-                     char atime_str[32], dtime_str[32], ctime_str[32];
-
-                     user_from_uid (user, sizeof (user), uid);
-                     group_from_gid (group, sizeof (group), gid);
-                     user_from_uid (cuser, sizeof (cuser), cuid);
-                     group_from_gid (cgroup, sizeof (cgroup), cgid);
-
-                     command_from_pid (ccmd, sizeof (ccmd), cpid);
-                     command_from_pid (lcmd, sizeof (lcmd), lpid);
-
-                     time_from_time_t (atime_str, sizeof (atime_str), atime);
-                     time_from_time_t (dtime_str, sizeof (dtime_str), dtime);
-                     time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
-
-                     buffer_xml_printf (
-                         &buffer,
-                         "<item>"
-                         "<column name=\"key\">%d</column>"
-                         "<column name=\"shmid\">%d</column>"
-                         "<column name=\"permissions\">%o</column>"
-                         "<column name=\"size\">%d</column>"
-                         "<column name=\"creator command\">%s</column>"
-                         "<column name=\"last op. command\">%s</column>"
-                         "<column name=\"num attached\">%d</column>"
-                         "<column name=\"user\">%s</column>"
-                         "<column name=\"group\">%s</column>"
-                         "<column name=\"creator user\">%s</column>"
-                         "<column name=\"creator group\">%s</column>"
-                         "<column name=\"last shmat() time\">%s</column>"
-                         "<column name=\"last shmdt() time\">%s</column>"
-                         "<column name=\"last shmctl() time\">%s</column>"
-                         "</item>",
-                         key,
-                         shmid,
-                         perms,
-                         size,
-                         ccmd,
-                         lcmd,
-                         nattch,
-                         user,
-                         group,
-                         cuser,
-                         cgroup,
-                         atime_str,
-                         dtime_str,
-                         ctime_str);
-                   }
+                 char user[UT_NAMESIZE], group[UT_NAMESIZE];
+                 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
+                 char ccmd[32], lcmd[32];
+                 char atime_str[32], dtime_str[32], ctime_str[32];
+
+                 user_from_uid (user, sizeof (user), uid);
+                 group_from_gid (group, sizeof (group), gid);
+                 user_from_uid (cuser, sizeof (cuser), cuid);
+                 group_from_gid (cgroup, sizeof (cgroup), cgid);
+
+                 command_from_pid (ccmd, sizeof (ccmd), cpid);
+                 command_from_pid (lcmd, sizeof (lcmd), lpid);
+
+                 time_from_time_t (atime_str, sizeof (atime_str), atime);
+                 time_from_time_t (dtime_str, sizeof (dtime_str), dtime);
+                 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
+
+                 buffer_xml_printf
+                   (buffer,
+                    "<item>"
+                    "<column name=\"key\">%d</column>"
+                    "<column name=\"shmid\">%d</column>"
+                    "<column name=\"permissions\">%o</column>"
+                    "<column name=\"size\">%d</column>"
+                    "<column name=\"creator command\">%s</column>"
+                    "<column name=\"last op. command\">%s</column>"
+                    "<column name=\"num attached\">%d</column>"
+                    "<column name=\"user\">%s</column>"
+                    "<column name=\"group\">%s</column>"
+                    "<column name=\"creator user\">%s</column>"
+                    "<column name=\"creator group\">%s</column>"
+                    "<column name=\"last shmat() time\">%s</column>"
+                    "<column name=\"last shmdt() time\">%s</column>"
+                    "<column name=\"last shmctl() time\">%s</column>"
+                    "</item>",
+                    key,
+                    shmid,
+                    perms,
+                    size,
+                    ccmd,
+                    lcmd,
+                    nattch,
+                    user,
+                    group,
+                    cuser,
+                    cgroup,
+                    atime_str,
+                    dtime_str,
+                    ctime_str);
                }
            }
-         while (!feof (fp.get ()));
        }
-
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      saved_buf = buffer_finish (&buffer);
-      len_avail = strlen (saved_buf);
-    }
-
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      saved_buf = NULL;
-      len_avail = 0;
-      return 0;
+      while (!feof (fp.get ()));
     }
 
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, saved_buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
 /* Collect data about semaphores recorded in /proc and write it
-   into READBUF.  */
+   into BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_sem (gdb_byte *readbuf,
-                      ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_sem (struct buffer *buffer)
 {
-  static const char *saved_buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  buffer_grow_str (buffer, "<osdata type=\"semaphores\">\n");
 
-  if (offset == 0)
+  gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
+  if (fp)
     {
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      saved_buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"semaphores\">\n");
-
-      gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
-      if (fp)
-       {
-         char buf[8192];
+      char buf[8192];
 
-         do
+      do
+       {
+         if (fgets (buf, sizeof (buf), fp.get ()))
            {
-             if (fgets (buf, sizeof (buf), fp.get ()))
+             key_t key;
+             uid_t uid, cuid;
+             gid_t gid, cgid;
+             unsigned int perms, nsems;
+             int semid;
+             TIME_T otime, ctime;
+             int items_read;
+
+             items_read = sscanf (buf,
+                                  "%d %d %o %u %d %d %d %d %lld %lld",
+                                  &key, &semid, &perms, &nsems,
+                                  &uid, &gid, &cuid, &cgid,
+                                  &otime, &ctime);
+
+             if (items_read == 10)
                {
-                 key_t key;
-                 uid_t uid, cuid;
-                 gid_t gid, cgid;
-                 unsigned int perms, nsems;
-                 int semid;
-                 TIME_T otime, ctime;
-                 int items_read;
-
-                 items_read = sscanf (buf,
-                                      "%d %d %o %u %d %d %d %d %lld %lld",
-                                      &key, &semid, &perms, &nsems,
-                                      &uid, &gid, &cuid, &cgid,
-                                      &otime, &ctime);
-
-                 if (items_read == 10)
-                   {
-                     char user[UT_NAMESIZE], group[UT_NAMESIZE];
-                     char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
-                     char otime_str[32], ctime_str[32];
-
-                     user_from_uid (user, sizeof (user), uid);
-                     group_from_gid (group, sizeof (group), gid);
-                     user_from_uid (cuser, sizeof (cuser), cuid);
-                     group_from_gid (cgroup, sizeof (cgroup), cgid);
-
-                     time_from_time_t (otime_str, sizeof (otime_str), otime);
-                     time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
-
-                     buffer_xml_printf (
-                         &buffer,
-                         "<item>"
-                         "<column name=\"key\">%d</column>"
-                         "<column name=\"semid\">%d</column>"
-                         "<column name=\"permissions\">%o</column>"
-                         "<column name=\"num semaphores\">%u</column>"
-                         "<column name=\"user\">%s</column>"
-                         "<column name=\"group\">%s</column>"
-                         "<column name=\"creator user\">%s</column>"
-                         "<column name=\"creator group\">%s</column>"
-                         "<column name=\"last semop() time\">%s</column>"
-                         "<column name=\"last semctl() time\">%s</column>"
-                         "</item>",
-                         key,
-                         semid,
-                         perms,
-                         nsems,
-                         user,
-                         group,
-                         cuser,
-                         cgroup,
-                         otime_str,
-                         ctime_str);
-                   }
+                 char user[UT_NAMESIZE], group[UT_NAMESIZE];
+                 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
+                 char otime_str[32], ctime_str[32];
+
+                 user_from_uid (user, sizeof (user), uid);
+                 group_from_gid (group, sizeof (group), gid);
+                 user_from_uid (cuser, sizeof (cuser), cuid);
+                 group_from_gid (cgroup, sizeof (cgroup), cgid);
+
+                 time_from_time_t (otime_str, sizeof (otime_str), otime);
+                 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
+
+                 buffer_xml_printf
+                   (buffer,
+                    "<item>"
+                    "<column name=\"key\">%d</column>"
+                    "<column name=\"semid\">%d</column>"
+                    "<column name=\"permissions\">%o</column>"
+                    "<column name=\"num semaphores\">%u</column>"
+                    "<column name=\"user\">%s</column>"
+                    "<column name=\"group\">%s</column>"
+                    "<column name=\"creator user\">%s</column>"
+                    "<column name=\"creator group\">%s</column>"
+                    "<column name=\"last semop() time\">%s</column>"
+                    "<column name=\"last semctl() time\">%s</column>"
+                    "</item>",
+                    key,
+                    semid,
+                    perms,
+                    nsems,
+                    user,
+                    group,
+                    cuser,
+                    cgroup,
+                    otime_str,
+                    ctime_str);
                }
            }
-         while (!feof (fp.get ()));
        }
-
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      saved_buf = buffer_finish (&buffer);
-      len_avail = strlen (saved_buf);
-    }
-
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      saved_buf = NULL;
-      len_avail = 0;
-      return 0;
+      while (!feof (fp.get ()));
     }
 
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, saved_buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
 /* Collect data about message queues recorded in /proc and write it
-   into READBUF.  */
+   into BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_msg (gdb_byte *readbuf,
-                      ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_msg (struct buffer *buffer)
 {
-  static const char *saved_buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  buffer_grow_str (buffer, "<osdata type=\"message queues\">\n");
 
-  if (offset == 0)
+  gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
+  if (fp)
     {
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      saved_buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"message queues\">\n");
-
-      gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
-      if (fp)
-       {
-         char buf[8192];
+      char buf[8192];
 
-         do
+      do
+       {
+         if (fgets (buf, sizeof (buf), fp.get ()))
            {
-             if (fgets (buf, sizeof (buf), fp.get ()))
+             key_t key;
+             PID_T lspid, lrpid;
+             uid_t uid, cuid;
+             gid_t gid, cgid;
+             unsigned int perms, cbytes, qnum;
+             int msqid;
+             TIME_T stime, rtime, ctime;
+             int items_read;
+
+             items_read = sscanf (buf,
+                                  "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
+                                  &key, &msqid, &perms, &cbytes, &qnum,
+                                  &lspid, &lrpid, &uid, &gid, &cuid, &cgid,
+                                  &stime, &rtime, &ctime);
+
+             if (items_read == 14)
                {
-                 key_t key;
-                 PID_T lspid, lrpid;
-                 uid_t uid, cuid;
-                 gid_t gid, cgid;
-                 unsigned int perms, cbytes, qnum;
-                 int msqid;
-                 TIME_T stime, rtime, ctime;
-                 int items_read;
-
-                 items_read = sscanf (buf,
-                                      "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
-                                      &key, &msqid, &perms, &cbytes, &qnum,
-                                      &lspid, &lrpid, &uid, &gid, &cuid, &cgid,
-                                      &stime, &rtime, &ctime);
-
-                 if (items_read == 14)
-                   {
-                     char user[UT_NAMESIZE], group[UT_NAMESIZE];
-                     char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
-                     char lscmd[32], lrcmd[32];
-                     char stime_str[32], rtime_str[32], ctime_str[32];
-
-                     user_from_uid (user, sizeof (user), uid);
-                     group_from_gid (group, sizeof (group), gid);
-                     user_from_uid (cuser, sizeof (cuser), cuid);
-                     group_from_gid (cgroup, sizeof (cgroup), cgid);
-
-                     command_from_pid (lscmd, sizeof (lscmd), lspid);
-                     command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
-
-                     time_from_time_t (stime_str, sizeof (stime_str), stime);
-                     time_from_time_t (rtime_str, sizeof (rtime_str), rtime);
-                     time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
-
-                     buffer_xml_printf (
-                         &buffer,
-                         "<item>"
-                         "<column name=\"key\">%d</column>"
-                         "<column name=\"msqid\">%d</column>"
-                         "<column name=\"permissions\">%o</column>"
-                         "<column name=\"num used bytes\">%u</column>"
-                         "<column name=\"num messages\">%u</column>"
-                         "<column name=\"last msgsnd() command\">%s</column>"
-                         "<column name=\"last msgrcv() command\">%s</column>"
-                         "<column name=\"user\">%s</column>"
-                         "<column name=\"group\">%s</column>"
-                         "<column name=\"creator user\">%s</column>"
-                         "<column name=\"creator group\">%s</column>"
-                         "<column name=\"last msgsnd() time\">%s</column>"
-                         "<column name=\"last msgrcv() time\">%s</column>"
-                         "<column name=\"last msgctl() time\">%s</column>"
-                         "</item>",
-                         key,
-                         msqid,
-                         perms,
-                         cbytes,
-                         qnum,
-                         lscmd,
-                         lrcmd,
-                         user,
-                         group,
-                         cuser,
-                         cgroup,
-                         stime_str,
-                         rtime_str,
-                         ctime_str);
-                   }
+                 char user[UT_NAMESIZE], group[UT_NAMESIZE];
+                 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
+                 char lscmd[32], lrcmd[32];
+                 char stime_str[32], rtime_str[32], ctime_str[32];
+
+                 user_from_uid (user, sizeof (user), uid);
+                 group_from_gid (group, sizeof (group), gid);
+                 user_from_uid (cuser, sizeof (cuser), cuid);
+                 group_from_gid (cgroup, sizeof (cgroup), cgid);
+
+                 command_from_pid (lscmd, sizeof (lscmd), lspid);
+                 command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
+
+                 time_from_time_t (stime_str, sizeof (stime_str), stime);
+                 time_from_time_t (rtime_str, sizeof (rtime_str), rtime);
+                 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
+
+                 buffer_xml_printf
+                   (buffer,
+                    "<item>"
+                    "<column name=\"key\">%d</column>"
+                    "<column name=\"msqid\">%d</column>"
+                    "<column name=\"permissions\">%o</column>"
+                    "<column name=\"num used bytes\">%u</column>"
+                    "<column name=\"num messages\">%u</column>"
+                    "<column name=\"last msgsnd() command\">%s</column>"
+                    "<column name=\"last msgrcv() command\">%s</column>"
+                    "<column name=\"user\">%s</column>"
+                    "<column name=\"group\">%s</column>"
+                    "<column name=\"creator user\">%s</column>"
+                    "<column name=\"creator group\">%s</column>"
+                    "<column name=\"last msgsnd() time\">%s</column>"
+                    "<column name=\"last msgrcv() time\">%s</column>"
+                    "<column name=\"last msgctl() time\">%s</column>"
+                    "</item>",
+                    key,
+                    msqid,
+                    perms,
+                    cbytes,
+                    qnum,
+                    lscmd,
+                    lrcmd,
+                    user,
+                    group,
+                    cuser,
+                    cgroup,
+                    stime_str,
+                    rtime_str,
+                    ctime_str);
                }
            }
-         while (!feof (fp.get ()));
        }
-
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      saved_buf = buffer_finish (&buffer);
-      len_avail = strlen (saved_buf);
-    }
-
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      saved_buf = NULL;
-      len_avail = 0;
-      return 0;
+      while (!feof (fp.get ()));
     }
 
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, saved_buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
 /* Collect data about loaded kernel modules and write it into
-   READBUF.  */
+   BUFFER.  */
 
-static LONGEST
-linux_xfer_osdata_modules (gdb_byte *readbuf,
-                          ULONGEST offset, ULONGEST len)
+static void
+linux_xfer_osdata_modules (struct buffer *buffer)
 {
-  static const char *saved_buf;
-  static LONGEST len_avail = -1;
-  static struct buffer buffer;
+  buffer_grow_str (buffer, "<osdata type=\"modules\">\n");
 
-  if (offset == 0)
+  gdb_file_up fp = gdb_fopen_cloexec ("/proc/modules", "r");
+  if (fp)
     {
-      if (len_avail != -1 && len_avail != 0)
-       buffer_free (&buffer);
-      len_avail = 0;
-      saved_buf = NULL;
-      buffer_init (&buffer);
-      buffer_grow_str (&buffer, "<osdata type=\"modules\">\n");
-
-      gdb_file_up fp = gdb_fopen_cloexec ("/proc/modules", "r");
-      if (fp)
-       {
-         char buf[8192];
+      char buf[8192];
 
-         do
+      do
+       {
+         if (fgets (buf, sizeof (buf), fp.get ()))
            {
-             if (fgets (buf, sizeof (buf), fp.get ()))
-               {
-                 char *name, *dependencies, *status, *tmp;
-                 unsigned int size;
-                 unsigned long long address;
-                 int uses;
+             char *name, *dependencies, *status, *tmp;
+             unsigned int size;
+             unsigned long long address;
+             int uses;
 
-                 name = strtok (buf, " ");
-                 if (name == NULL)
-                   continue;
+             name = strtok (buf, " ");
+             if (name == NULL)
+               continue;
 
-                 tmp = strtok (NULL, " ");
-                 if (tmp == NULL)
-                   continue;
-                 if (sscanf (tmp, "%u", &size) != 1)
-                   continue;
+             tmp = strtok (NULL, " ");
+             if (tmp == NULL)
+               continue;
+             if (sscanf (tmp, "%u", &size) != 1)
+               continue;
 
-                 tmp = strtok (NULL, " ");
-                 if (tmp == NULL)
-                   continue;
-                 if (sscanf (tmp, "%d", &uses) != 1)
-                   continue;
+             tmp = strtok (NULL, " ");
+             if (tmp == NULL)
+               continue;
+             if (sscanf (tmp, "%d", &uses) != 1)
+               continue;
 
-                 dependencies = strtok (NULL, " ");
-                 if (dependencies == NULL)
-                   continue;
+             dependencies = strtok (NULL, " ");
+             if (dependencies == NULL)
+               continue;
 
-                 status = strtok (NULL, " ");
-                 if (status == NULL)
-                   continue;
+             status = strtok (NULL, " ");
+             if (status == NULL)
+               continue;
 
-                 tmp = strtok (NULL, "\n");
-                 if (tmp == NULL)
-                   continue;
-                 if (sscanf (tmp, "%llx", &address) != 1)
-                   continue;
+             tmp = strtok (NULL, "\n");
+             if (tmp == NULL)
+               continue;
+             if (sscanf (tmp, "%llx", &address) != 1)
+               continue;
 
-                 buffer_xml_printf (
-                       &buffer,
-                       "<item>"
-                       "<column name=\"name\">%s</column>"
-                       "<column name=\"size\">%u</column>"
-                       "<column name=\"num uses\">%d</column>"
-                       "<column name=\"dependencies\">%s</column>"
-                       "<column name=\"status\">%s</column>"
-                       "<column name=\"address\">%llx</column>"
-                       "</item>",
-                       name,
-                       size,
-                       uses,
-                       dependencies,
-                       status,
-                       address);
-               }
+             buffer_xml_printf (buffer,
+                                "<item>"
+                                "<column name=\"name\">%s</column>"
+                                "<column name=\"size\">%u</column>"
+                                "<column name=\"num uses\">%d</column>"
+                                "<column name=\"dependencies\">%s</column>"
+                                "<column name=\"status\">%s</column>"
+                                "<column name=\"address\">%llx</column>"
+                                "</item>",
+                                name,
+                                size,
+                                uses,
+                                dependencies,
+                                status,
+                                address);
            }
-         while (!feof (fp.get ()));
        }
-
-      buffer_grow_str0 (&buffer, "</osdata>\n");
-      saved_buf = buffer_finish (&buffer);
-      len_avail = strlen (saved_buf);
-    }
-
-  if (offset >= len_avail)
-    {
-      /* Done.  Get rid of the buffer.  */
-      buffer_free (&buffer);
-      saved_buf = NULL;
-      len_avail = 0;
-      return 0;
+      while (!feof (fp.get ()));
     }
 
-  if (len > len_avail - offset)
-    len = len_avail - offset;
-  memcpy (readbuf, saved_buf + offset, len);
-
-  return len;
+  buffer_grow_str0 (buffer, "</osdata>\n");
 }
 
+static void
+linux_xfer_osdata_info_os_types (struct buffer *buffer);
+
 struct osdata_type {
   const char *type;
   const char *title;
   const char *description;
-  LONGEST (*getter) (gdb_byte *readbuf, ULONGEST offset, ULONGEST len);
+  void (*take_snapshot) (struct buffer *buffer);
+  LONGEST len_avail;
+  struct buffer buffer;
 } osdata_table[] = {
+  { "types", "Types", "Listing of info os types you can list",
+    linux_xfer_osdata_info_os_types, -1 },
   { "cpus", "CPUs", "Listing of all cpus/cores on the system",
-    linux_xfer_osdata_cpus },
+    linux_xfer_osdata_cpus, -1 },
   { "files", "File descriptors", "Listing of all file descriptors",
-    linux_xfer_osdata_fds },
+    linux_xfer_osdata_fds, -1 },
   { "modules", "Kernel modules", "Listing of all loaded kernel modules",
-    linux_xfer_osdata_modules },
+    linux_xfer_osdata_modules, -1 },
   { "msg", "Message queues", "Listing of all message queues",
-    linux_xfer_osdata_msg },
+    linux_xfer_osdata_msg, -1 },
   { "processes", "Processes", "Listing of all processes",
-    linux_xfer_osdata_processes },
+    linux_xfer_osdata_processes, -1 },
   { "procgroups", "Process groups", "Listing of all process groups",
-    linux_xfer_osdata_processgroups },
+    linux_xfer_osdata_processgroups, -1 },
   { "semaphores", "Semaphores", "Listing of all semaphores",
-    linux_xfer_osdata_sem },
+    linux_xfer_osdata_sem, -1 },
   { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
-    linux_xfer_osdata_shm },
+    linux_xfer_osdata_shm, -1 },
   { "sockets", "Sockets", "Listing of all internet-domain sockets",
-    linux_xfer_osdata_isockets },
+    linux_xfer_osdata_isockets, -1 },
   { "threads", "Threads", "Listing of all threads",
-    linux_xfer_osdata_threads },
+  linux_xfer_osdata_threads, -1 },
   { NULL, NULL, NULL }
 };
 
-LONGEST
-linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
-                         ULONGEST offset, ULONGEST len)
+/* Collect data about all types info os can show in BUFFER.  */
+
+static void
+linux_xfer_osdata_info_os_types (struct buffer *buffer)
 {
-  if (!annex || *annex == '\0')
-    {
-      static const char *buf;
-      static LONGEST len_avail = -1;
-      static struct buffer buffer;
+  buffer_grow_str (buffer, "<osdata type=\"types\">\n");
+
+  /* Start the below loop at 1, as we do not want to list ourselves.  */
+  for (int i = 1; osdata_table[i].type; ++i)
+    buffer_xml_printf (buffer,
+                      "<item>"
+                      "<column name=\"Type\">%s</column>"
+                      "<column name=\"Description\">%s</column>"
+                      "<column name=\"Title\">%s</column>"
+                      "</item>",
+                      osdata_table[i].type,
+                      osdata_table[i].description,
+                      osdata_table[i].title);
+
+  buffer_grow_str0 (buffer, "</osdata>\n");
+}
 
-      if (offset == 0)
-       {
-         int i;
 
-         if (len_avail != -1 && len_avail != 0)
-           buffer_free (&buffer);
-         len_avail = 0;
-         buf = NULL;
-         buffer_init (&buffer);
-         buffer_grow_str (&buffer, "<osdata type=\"types\">\n");
-
-         for (i = 0; osdata_table[i].type; ++i)
-           buffer_xml_printf (
-                              &buffer,
-                              "<item>"
-                              "<column name=\"Type\">%s</column>"
-                              "<column name=\"Description\">%s</column>"
-                              "<column name=\"Title\">%s</column>"
-                              "</item>",
-                              osdata_table[i].type,
-                              osdata_table[i].description,
-                              osdata_table[i].title);
-
-         buffer_grow_str0 (&buffer, "</osdata>\n");
-         buf = buffer_finish (&buffer);
-         len_avail = strlen (buf);
-       }
+/*  Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
+    If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT.  */
 
-      if (offset >= len_avail)
-       {
-         /* Done.  Get rid of the buffer.  */
-         buffer_free (&buffer);
-         buf = NULL;
-         len_avail = 0;
-         return 0;
-       }
+static LONGEST
+common_getter (struct osdata_type *osd,
+              gdb_byte *readbuf, ULONGEST offset, ULONGEST len)
+{
+  gdb_assert (readbuf);
+
+  if (offset == 0)
+    {
+      if (osd->len_avail != -1 && osd->len_avail != 0)
+       buffer_free (&osd->buffer);
+      osd->len_avail = 0;
+      buffer_init (&osd->buffer);
+      (osd->take_snapshot) (&osd->buffer);
+      osd->len_avail = strlen (osd->buffer.buffer);
+    }
+  if (offset >= osd->len_avail)
+    {
+      /* Done.  Get rid of the buffer.  */
+      buffer_free (&osd->buffer);
+      osd->len_avail = 0;
+      return 0;
+    }
+  if (len > osd->len_avail - offset)
+    len = osd->len_avail - offset;
+  memcpy (readbuf, osd->buffer.buffer + offset, len);
 
-      if (len > len_avail - offset)
-       len = len_avail - offset;
-      memcpy (readbuf, buf + offset, len);
+  return len;
+
+}
 
-      return len;
+LONGEST
+linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
+                         ULONGEST offset, ULONGEST len)
+{
+  if (!annex || *annex == '\0')
+    {
+      return common_getter (&osdata_table[0],
+                           readbuf, offset, len);
     }
   else
     {
@@ -1668,11 +1382,8 @@ linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
       for (i = 0; osdata_table[i].type; ++i)
        {
          if (strcmp (annex, osdata_table[i].type) == 0)
-           {
-             gdb_assert (readbuf);
-
-             return (osdata_table[i].getter) (readbuf, offset, len);
-           }
+           return common_getter (&osdata_table[i],
+                                 readbuf, offset, len);
        }
 
       return 0;