GDB (API)
/home/stan/gdb/src/gdb/common/linux-osdata.c
Go to the documentation of this file.
00001 /* Linux-specific functions to retrieve OS data.
00002    
00003    Copyright (C) 2009-2013 Free Software Foundation, Inc.
00004 
00005    This file is part of GDB.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 3 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00019 
00020 #ifdef GDBSERVER
00021 #include "server.h"
00022 #else
00023 #include "defs.h"
00024 #endif
00025 
00026 #include "linux-osdata.h"
00027 
00028 #include <sys/types.h>
00029 #include <sys/sysinfo.h>
00030 #include <ctype.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <utmp.h>
00034 #include <time.h>
00035 #include <unistd.h>
00036 #include <pwd.h>
00037 #include <grp.h>
00038 #include <netdb.h>
00039 #include <netinet/in.h>
00040 #include <arpa/inet.h>
00041 
00042 #include "xml-utils.h"
00043 #include "buffer.h"
00044 #include "gdb_assert.h"
00045 #include "gdb_dirent.h"
00046 #include "gdb_stat.h"
00047 #include "filestuff.h"
00048 
00049 /* Define PID_T to be a fixed size that is at least as large as pid_t,
00050    so that reading pid values embedded in /proc works
00051    consistently.  */
00052 
00053 typedef long long  PID_T;
00054 
00055 /* Define TIME_T to be at least as large as time_t, so that reading
00056    time values embedded in /proc works consistently.  */
00057 
00058 typedef long long TIME_T;
00059 
00060 #define MAX_PID_T_STRLEN  (sizeof ("-9223372036854775808") - 1)
00061 
00062 /* Returns the CPU core that thread PTID is currently running on.  */
00063                                           
00064 /* Compute and return the processor core of a given thread.  */
00065 
00066 int
00067 linux_common_core_of_thread (ptid_t ptid)
00068 {
00069   char filename[sizeof ("/proc//task//stat") + 2 * MAX_PID_T_STRLEN];
00070   FILE *f;
00071   char *content = NULL;
00072   char *p;
00073   char *ts = 0;
00074   int content_read = 0;
00075   int i;
00076   int core;
00077 
00078   sprintf (filename, "/proc/%lld/task/%lld/stat",
00079            (PID_T) ptid_get_pid (ptid), (PID_T) ptid_get_lwp (ptid));
00080   f = gdb_fopen_cloexec (filename, "r");
00081   if (!f)
00082     return -1;
00083 
00084   for (;;)
00085     {
00086       int n;
00087       content = xrealloc (content, content_read + 1024);
00088       n = fread (content + content_read, 1, 1024, f);
00089       content_read += n;
00090       if (n < 1024)
00091         {
00092           content[content_read] = '\0';
00093           break;
00094         }
00095     }
00096 
00097   p = strchr (content, '(');
00098 
00099   /* Skip ")".  */
00100   if (p != NULL)
00101     p = strchr (p, ')');
00102   if (p != NULL)
00103     p++;
00104 
00105   /* If the first field after program name has index 0, then core number is
00106      the field with index 36.  There's no constant for that anywhere.  */
00107   if (p != NULL)
00108     p = strtok_r (p, " ", &ts);
00109   for (i = 0; p != NULL && i != 36; ++i)
00110     p = strtok_r (NULL, " ", &ts);
00111 
00112   if (p == NULL || sscanf (p, "%d", &core) == 0)
00113     core = -1;
00114 
00115   xfree (content);
00116   fclose (f);
00117 
00118   return core;
00119 }
00120 
00121 /* Finds the command-line of process PID and copies it into COMMAND.
00122    At most MAXLEN characters are copied.  If the command-line cannot
00123    be found, PID is copied into command in text-form.  */
00124 
00125 static void
00126 command_from_pid (char *command, int maxlen, PID_T pid)
00127 {
00128   char *stat_path = xstrprintf ("/proc/%lld/stat", pid); 
00129   FILE *fp = gdb_fopen_cloexec (stat_path, "r");
00130   
00131   command[0] = '\0';
00132  
00133   if (fp)
00134     {
00135       /* sizeof (cmd) should be greater or equal to TASK_COMM_LEN (in
00136          include/linux/sched.h in the Linux kernel sources) plus two
00137          (for the brackets).  */
00138       char cmd[32]; 
00139       PID_T stat_pid;
00140       int items_read = fscanf (fp, "%lld %32s", &stat_pid, cmd);
00141           
00142       if (items_read == 2 && pid == stat_pid)
00143         {
00144           cmd[strlen (cmd) - 1] = '\0'; /* Remove trailing parenthesis.  */
00145           strncpy (command, cmd + 1, maxlen); /* Ignore leading parenthesis.  */
00146         }
00147 
00148       fclose (fp);
00149     }
00150   else
00151     {
00152       /* Return the PID if a /proc entry for the process cannot be found.  */
00153       snprintf (command, maxlen, "%lld", pid);
00154     }
00155 
00156   command[maxlen - 1] = '\0'; /* Ensure string is null-terminated.  */
00157         
00158   xfree (stat_path);
00159 }
00160 
00161 /* Returns the command-line of the process with the given PID. The
00162    returned string needs to be freed using xfree after use.  */
00163 
00164 static char *
00165 commandline_from_pid (PID_T pid)
00166 {
00167   char *pathname = xstrprintf ("/proc/%lld/cmdline", pid);
00168   char *commandline = NULL;
00169   FILE *f = gdb_fopen_cloexec (pathname, "r");
00170 
00171   if (f)
00172     {
00173       size_t len = 0;
00174 
00175       while (!feof (f))
00176         {
00177           char buf[1024];
00178           size_t read_bytes = fread (buf, 1, sizeof (buf), f);
00179      
00180           if (read_bytes)
00181             {
00182               commandline = (char *) xrealloc (commandline, len + read_bytes + 1);
00183               memcpy (commandline + len, buf, read_bytes);
00184               len += read_bytes;
00185             }
00186         }
00187 
00188       fclose (f);
00189 
00190       if (commandline)
00191         {
00192           size_t i;
00193 
00194           /* Replace null characters with spaces.  */
00195           for (i = 0; i < len; ++i)
00196             if (commandline[i] == '\0')
00197               commandline[i] = ' ';
00198 
00199           commandline[len] = '\0';
00200         }
00201       else
00202         {
00203           /* Return the command in square brackets if the command-line
00204              is empty.  */
00205           commandline = (char *) xmalloc (32);
00206           commandline[0] = '[';
00207           command_from_pid (commandline + 1, 31, pid);
00208 
00209           len = strlen (commandline);
00210           if (len < 31)
00211             strcat (commandline, "]");
00212         }
00213     }
00214 
00215   xfree (pathname);
00216 
00217   return commandline;
00218 }
00219 
00220 /* Finds the user name for the user UID and copies it into USER.  At
00221    most MAXLEN characters are copied.  */
00222 
00223 static void
00224 user_from_uid (char *user, int maxlen, uid_t uid)
00225 {
00226   struct passwd *pwentry = getpwuid (uid);
00227   
00228   if (pwentry)
00229     {
00230       strncpy (user, pwentry->pw_name, maxlen);
00231       /* Ensure that the user name is null-terminated.  */
00232       user[maxlen - 1] = '\0';
00233     }
00234   else
00235     user[0] = '\0';
00236 }
00237 
00238 /* Finds the owner of process PID and returns the user id in OWNER.
00239    Returns 0 if the owner was found, -1 otherwise.  */
00240 
00241 static int
00242 get_process_owner (uid_t *owner, PID_T pid)
00243 {
00244   struct stat statbuf;
00245   char procentry[sizeof ("/proc/") + MAX_PID_T_STRLEN];
00246 
00247   sprintf (procentry, "/proc/%lld", pid);
00248   
00249   if (stat (procentry, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
00250     {
00251       *owner = statbuf.st_uid;
00252       return 0;
00253     }
00254   else
00255     return -1;
00256 }
00257 
00258 /* Find the CPU cores used by process PID and return them in CORES.
00259    CORES points to an array of at least sysconf(_SC_NPROCESSOR_ONLN)
00260    elements.  */
00261 
00262 static int
00263 get_cores_used_by_process (PID_T pid, int *cores)
00264 {
00265   char taskdir[sizeof ("/proc/") + MAX_PID_T_STRLEN + sizeof ("/task") - 1];
00266   DIR *dir;
00267   struct dirent *dp;
00268   int task_count = 0;
00269 
00270   sprintf (taskdir, "/proc/%lld/task", pid);
00271   dir = opendir (taskdir);
00272   if (dir)
00273     {
00274       while ((dp = readdir (dir)) != NULL)
00275         {
00276           PID_T tid;
00277           int core;
00278 
00279           if (!isdigit (dp->d_name[0])
00280               || NAMELEN (dp) > MAX_PID_T_STRLEN)
00281             continue;
00282 
00283           sscanf (dp->d_name, "%lld", &tid);
00284           core = linux_common_core_of_thread (ptid_build ((pid_t) pid,
00285                                                           (pid_t) tid, 0));
00286 
00287           if (core >= 0)
00288             {
00289               ++cores[core];
00290               ++task_count;
00291             }
00292         }
00293 
00294       closedir (dir);
00295     }
00296 
00297   return task_count;
00298 }
00299 
00300 static LONGEST
00301 linux_xfer_osdata_processes (gdb_byte *readbuf,
00302                              ULONGEST offset, LONGEST len)
00303 {
00304   /* We make the process list snapshot when the object starts to be read.  */
00305   static const char *buf;
00306   static LONGEST len_avail = -1;
00307   static struct buffer buffer;
00308 
00309   if (offset == 0)
00310     {
00311       DIR *dirp;
00312 
00313       if (len_avail != -1 && len_avail != 0)
00314         buffer_free (&buffer);
00315       len_avail = 0;
00316       buf = NULL;
00317       buffer_init (&buffer);
00318       buffer_grow_str (&buffer, "<osdata type=\"processes\">\n");
00319 
00320       dirp = opendir ("/proc");
00321       if (dirp)
00322         {
00323           const int num_cores = sysconf (_SC_NPROCESSORS_ONLN);
00324           struct dirent *dp;
00325 
00326           while ((dp = readdir (dirp)) != NULL)
00327             {
00328               PID_T pid;
00329               uid_t owner;
00330               char user[UT_NAMESIZE];
00331               char *command_line;
00332               int *cores;
00333               int task_count;
00334               char *cores_str;
00335               int i;
00336 
00337               if (!isdigit (dp->d_name[0])
00338                   || NAMELEN (dp) > MAX_PID_T_STRLEN)
00339                 continue;
00340 
00341               sscanf (dp->d_name, "%lld", &pid);
00342               command_line = commandline_from_pid (pid);
00343 
00344               if (get_process_owner (&owner, pid) == 0)
00345                 user_from_uid (user, sizeof (user), owner);
00346               else
00347                 strcpy (user, "?");
00348 
00349               /* Find CPU cores used by the process.  */
00350               cores = (int *) xcalloc (num_cores, sizeof (int));
00351               task_count = get_cores_used_by_process (pid, cores);
00352               cores_str = (char *) xcalloc (task_count, sizeof ("4294967295") + 1);
00353 
00354               for (i = 0; i < num_cores && task_count > 0; ++i)
00355                 if (cores[i])
00356                   {
00357                     char core_str[sizeof ("4294967295")];
00358 
00359                     sprintf (core_str, "%d", i);
00360                     strcat (cores_str, core_str);
00361 
00362                     task_count -= cores[i];
00363                     if (task_count > 0)
00364                       strcat (cores_str, ",");
00365                   }
00366 
00367               xfree (cores);
00368               
00369               buffer_xml_printf (
00370                   &buffer,
00371                   "<item>"
00372                   "<column name=\"pid\">%lld</column>"
00373                   "<column name=\"user\">%s</column>"
00374                   "<column name=\"command\">%s</column>"
00375                   "<column name=\"cores\">%s</column>"
00376                   "</item>",
00377                   pid,
00378                   user,
00379                   command_line ? command_line : "",
00380                   cores_str);
00381 
00382               xfree (command_line);     
00383               xfree (cores_str);
00384             }
00385           
00386           closedir (dirp);
00387         }
00388 
00389       buffer_grow_str0 (&buffer, "</osdata>\n");
00390       buf = buffer_finish (&buffer);
00391       len_avail = strlen (buf);
00392     }
00393 
00394   if (offset >= len_avail)
00395     {
00396       /* Done.  Get rid of the buffer.  */
00397       buffer_free (&buffer);
00398       buf = NULL;
00399       len_avail = 0;
00400       return 0;
00401     }
00402 
00403   if (len > len_avail - offset)
00404     len = len_avail - offset;
00405   memcpy (readbuf, buf + offset, len);
00406 
00407   return len;
00408 }
00409 
00410 /* Auxiliary function used by qsort to sort processes by process
00411    group.  Compares two processes with ids PROCESS1 and PROCESS2.
00412    PROCESS1 comes before PROCESS2 if it has a lower process group id.
00413    If they belong to the same process group, PROCESS1 comes before
00414    PROCESS2 if it has a lower process id or is the process group
00415    leader.  */
00416 
00417 static int
00418 compare_processes (const void *process1, const void *process2)
00419 {
00420   PID_T pid1 = *((PID_T *) process1);
00421   PID_T pid2 = *((PID_T *) process2);
00422   PID_T pgid1 = *((PID_T *) process1 + 1);
00423   PID_T pgid2 = *((PID_T *) process2 + 1);
00424 
00425   /* Sort by PGID.  */
00426   if (pgid1 < pgid2)
00427     return -1;
00428   else if (pgid1 > pgid2)
00429     return 1;
00430   else
00431     {
00432       /* Process group leaders always come first, else sort by PID.  */
00433       if (pid1 == pgid1)
00434         return -1;
00435       else if (pid2 == pgid2)
00436         return 1;
00437       else if (pid1 < pid2)
00438         return -1;
00439       else if (pid1 > pid2)
00440         return 1;
00441       else
00442         return 0;
00443     }
00444 }
00445 
00446 /* Collect all process groups from /proc.  */
00447 
00448 static LONGEST
00449 linux_xfer_osdata_processgroups (gdb_byte *readbuf,
00450                                  ULONGEST offset, LONGEST len)
00451 {
00452   /* We make the process list snapshot when the object starts to be read.  */
00453   static const char *buf;
00454   static LONGEST len_avail = -1;
00455   static struct buffer buffer;
00456 
00457   if (offset == 0)
00458     {
00459       DIR *dirp;
00460 
00461       if (len_avail != -1 && len_avail != 0)
00462         buffer_free (&buffer);
00463       len_avail = 0;
00464       buf = NULL;
00465       buffer_init (&buffer);
00466       buffer_grow_str (&buffer, "<osdata type=\"process groups\">\n");
00467 
00468       dirp = opendir ("/proc");
00469       if (dirp)
00470         {
00471           struct dirent *dp;
00472           const size_t list_block_size = 512;
00473           PID_T *process_list = (PID_T *) xmalloc (list_block_size * 2 * sizeof (PID_T));
00474           size_t process_count = 0;
00475           size_t i;
00476 
00477           /* Build list consisting of PIDs followed by their
00478              associated PGID.  */
00479           while ((dp = readdir (dirp)) != NULL)
00480             {
00481               PID_T pid, pgid;
00482 
00483               if (!isdigit (dp->d_name[0])
00484                   || NAMELEN (dp) > MAX_PID_T_STRLEN)
00485                 continue;
00486 
00487               sscanf (dp->d_name, "%lld", &pid);
00488               pgid = getpgid (pid);
00489 
00490               if (pgid > 0)
00491                 {
00492                   process_list[2 * process_count] = pid;
00493                   process_list[2 * process_count + 1] = pgid;
00494                   ++process_count;
00495 
00496                   /* Increase the size of the list if necessary.  */
00497                   if (process_count % list_block_size == 0)
00498                     process_list = (PID_T *) xrealloc (
00499                         process_list,
00500                         (process_count + list_block_size)
00501                         * 2 * sizeof (PID_T));
00502                 }
00503             }
00504 
00505           closedir (dirp);
00506 
00507           /* Sort the process list.  */
00508           qsort (process_list, process_count, 2 * sizeof (PID_T),
00509                  compare_processes);
00510 
00511           for (i = 0; i < process_count; ++i)
00512             {
00513               PID_T pid = process_list[2 * i];
00514               PID_T pgid = process_list[2 * i + 1];
00515               char leader_command[32];
00516               char *command_line;
00517 
00518               command_from_pid (leader_command, sizeof (leader_command), pgid);
00519               command_line = commandline_from_pid (pid);
00520 
00521               buffer_xml_printf (
00522                   &buffer,
00523                   "<item>"
00524                   "<column name=\"pgid\">%lld</column>"
00525                   "<column name=\"leader command\">%s</column>"
00526                   "<column name=\"pid\">%lld</column>"
00527                   "<column name=\"command line\">%s</column>"
00528                   "</item>",
00529                   pgid,
00530                   leader_command,
00531                   pid,
00532                   command_line ? command_line : "");
00533 
00534               xfree (command_line);
00535             }
00536 
00537           xfree (process_list);
00538         }   
00539 
00540       buffer_grow_str0 (&buffer, "</osdata>\n");
00541       buf = buffer_finish (&buffer);
00542       len_avail = strlen (buf);
00543     }
00544 
00545   if (offset >= len_avail)
00546     {
00547       /* Done.  Get rid of the buffer.  */
00548       buffer_free (&buffer);
00549       buf = NULL;
00550       len_avail = 0;
00551       return 0;
00552     }
00553 
00554   if (len > len_avail - offset)
00555     len = len_avail - offset;
00556   memcpy (readbuf, buf + offset, len);
00557 
00558   return len;
00559 }
00560 
00561 /* Collect all the threads in /proc by iterating through processes and
00562    then tasks within each process.  */
00563 
00564 static LONGEST
00565 linux_xfer_osdata_threads (gdb_byte *readbuf,
00566                            ULONGEST offset, LONGEST len)
00567 {
00568   /* We make the process list snapshot when the object starts to be read.  */
00569   static const char *buf;
00570   static LONGEST len_avail = -1;
00571   static struct buffer buffer;
00572 
00573   if (offset == 0)
00574     {
00575       DIR *dirp;
00576 
00577       if (len_avail != -1 && len_avail != 0)
00578         buffer_free (&buffer);
00579       len_avail = 0;
00580       buf = NULL;
00581       buffer_init (&buffer);
00582       buffer_grow_str (&buffer, "<osdata type=\"threads\">\n");
00583 
00584       dirp = opendir ("/proc");
00585       if (dirp)
00586         {
00587           struct dirent *dp;
00588 
00589           while ((dp = readdir (dirp)) != NULL)
00590             {
00591               struct stat statbuf;
00592               char procentry[sizeof ("/proc/4294967295")];
00593 
00594               if (!isdigit (dp->d_name[0])
00595                   || NAMELEN (dp) > sizeof ("4294967295") - 1)
00596                 continue;
00597 
00598               sprintf (procentry, "/proc/%s", dp->d_name);
00599               if (stat (procentry, &statbuf) == 0
00600                   && S_ISDIR (statbuf.st_mode))
00601                 {
00602                   DIR *dirp2;
00603                   char *pathname;
00604                   PID_T pid;
00605                   char command[32];
00606 
00607                   pathname = xstrprintf ("/proc/%s/task", dp->d_name);
00608                   
00609                   pid = atoi (dp->d_name);
00610                   command_from_pid (command, sizeof (command), pid);
00611 
00612                   dirp2 = opendir (pathname);
00613 
00614                   if (dirp2)
00615                     {
00616                       struct dirent *dp2;
00617 
00618                       while ((dp2 = readdir (dirp2)) != NULL)
00619                         {
00620                           PID_T tid;
00621                           int core;
00622 
00623                           if (!isdigit (dp2->d_name[0])
00624                               || NAMELEN (dp2) > sizeof ("4294967295") - 1)
00625                             continue;
00626 
00627                           tid = atoi (dp2->d_name);
00628                           core = linux_common_core_of_thread (ptid_build (pid, tid, 0));
00629 
00630                           buffer_xml_printf (
00631                             &buffer,
00632                             "<item>"
00633                             "<column name=\"pid\">%lld</column>"
00634                             "<column name=\"command\">%s</column>"
00635                             "<column name=\"tid\">%lld</column>"
00636                             "<column name=\"core\">%d</column>"
00637                             "</item>",
00638                             pid,
00639                             command,
00640                             tid,
00641                             core);
00642                         }
00643 
00644                       closedir (dirp2);
00645                     }
00646 
00647                   xfree (pathname);
00648                 }
00649             }
00650 
00651           closedir (dirp);
00652         }
00653 
00654       buffer_grow_str0 (&buffer, "</osdata>\n");
00655       buf = buffer_finish (&buffer);
00656       len_avail = strlen (buf);
00657     }
00658 
00659   if (offset >= len_avail)
00660     {
00661       /* Done.  Get rid of the buffer.  */
00662       buffer_free (&buffer);
00663       buf = NULL;
00664       len_avail = 0;
00665       return 0;
00666     }
00667 
00668   if (len > len_avail - offset)
00669     len = len_avail - offset;
00670   memcpy (readbuf, buf + offset, len);
00671 
00672   return len;
00673 }
00674 
00675 /* Collect all the open file descriptors found in /proc and put the details
00676    found about them into READBUF.  */
00677 
00678 static LONGEST
00679 linux_xfer_osdata_fds (gdb_byte *readbuf,
00680                        ULONGEST offset, LONGEST len)
00681 {
00682   /* We make the process list snapshot when the object starts to be read.  */
00683   static const char *buf;
00684   static LONGEST len_avail = -1;
00685   static struct buffer buffer;
00686 
00687   if (offset == 0)
00688     {
00689       DIR *dirp;
00690 
00691       if (len_avail != -1 && len_avail != 0)
00692         buffer_free (&buffer);
00693       len_avail = 0;
00694       buf = NULL;
00695       buffer_init (&buffer);
00696       buffer_grow_str (&buffer, "<osdata type=\"files\">\n");
00697 
00698       dirp = opendir ("/proc");
00699       if (dirp)
00700         {
00701           struct dirent *dp;
00702 
00703           while ((dp = readdir (dirp)) != NULL)
00704             {
00705               struct stat statbuf;
00706               char procentry[sizeof ("/proc/4294967295")];
00707 
00708               if (!isdigit (dp->d_name[0])
00709                   || NAMELEN (dp) > sizeof ("4294967295") - 1)
00710                 continue;
00711 
00712               sprintf (procentry, "/proc/%s", dp->d_name);
00713               if (stat (procentry, &statbuf) == 0
00714                   && S_ISDIR (statbuf.st_mode))
00715                 {
00716                   char *pathname;
00717                   DIR *dirp2;
00718                   PID_T pid;
00719                   char command[32];
00720 
00721                   pid = atoi (dp->d_name);
00722                   command_from_pid (command, sizeof (command), pid);
00723 
00724                   pathname = xstrprintf ("/proc/%s/fd", dp->d_name);
00725                   dirp2 = opendir (pathname);
00726 
00727                   if (dirp2)
00728                     {
00729                       struct dirent *dp2;
00730 
00731                       while ((dp2 = readdir (dirp2)) != NULL)
00732                         {
00733                           char *fdname;
00734                           char buf[1000];
00735                           ssize_t rslt;
00736 
00737                           if (!isdigit (dp2->d_name[0]))
00738                             continue;
00739 
00740                           fdname = xstrprintf ("%s/%s", pathname, dp2->d_name);
00741                           rslt = readlink (fdname, buf, sizeof (buf) - 1);
00742                           if (rslt >= 0)
00743                             buf[rslt] = '\0';
00744 
00745                           buffer_xml_printf (
00746                             &buffer,
00747                             "<item>"
00748                             "<column name=\"pid\">%s</column>"
00749                             "<column name=\"command\">%s</column>"
00750                             "<column name=\"file descriptor\">%s</column>"
00751                             "<column name=\"name\">%s</column>"
00752                             "</item>",
00753                             dp->d_name,
00754                             command,
00755                             dp2->d_name,
00756                             (rslt >= 0 ? buf : dp2->d_name));
00757                         }
00758 
00759                       closedir (dirp2);
00760                     }
00761 
00762                   xfree (pathname);
00763                 }
00764             }
00765 
00766           closedir (dirp);
00767         }
00768 
00769       buffer_grow_str0 (&buffer, "</osdata>\n");
00770       buf = buffer_finish (&buffer);
00771       len_avail = strlen (buf);
00772     }
00773 
00774   if (offset >= len_avail)
00775     {
00776       /* Done.  Get rid of the buffer.  */
00777       buffer_free (&buffer);
00778       buf = NULL;
00779       len_avail = 0;
00780       return 0;
00781     }
00782 
00783   if (len > len_avail - offset)
00784     len = len_avail - offset;
00785   memcpy (readbuf, buf + offset, len);
00786 
00787   return len;
00788 }
00789 
00790 /* Returns the socket state STATE in textual form.  */
00791 
00792 static const char *
00793 format_socket_state (unsigned char state)
00794 {
00795   /* Copied from include/net/tcp_states.h in the Linux kernel sources.  */
00796   enum {
00797     TCP_ESTABLISHED = 1,
00798     TCP_SYN_SENT,
00799     TCP_SYN_RECV,
00800     TCP_FIN_WAIT1,
00801     TCP_FIN_WAIT2,
00802     TCP_TIME_WAIT,
00803     TCP_CLOSE,
00804     TCP_CLOSE_WAIT,
00805     TCP_LAST_ACK,
00806     TCP_LISTEN,
00807     TCP_CLOSING
00808   };
00809 
00810   switch (state)
00811     {
00812     case TCP_ESTABLISHED:
00813       return "ESTABLISHED";
00814     case TCP_SYN_SENT:
00815       return "SYN_SENT";
00816     case TCP_SYN_RECV:
00817       return "SYN_RECV";
00818     case TCP_FIN_WAIT1:
00819       return "FIN_WAIT1";
00820     case TCP_FIN_WAIT2:
00821       return "FIN_WAIT2";
00822     case TCP_TIME_WAIT:
00823       return "TIME_WAIT";
00824     case TCP_CLOSE:
00825       return "CLOSE";
00826     case TCP_CLOSE_WAIT:
00827       return "CLOSE_WAIT";
00828     case TCP_LAST_ACK:
00829       return "LAST_ACK";
00830     case TCP_LISTEN:
00831       return "LISTEN";
00832     case TCP_CLOSING:
00833       return "CLOSING";
00834     default:
00835       return "(unknown)";
00836     }
00837 }
00838 
00839 union socket_addr
00840   {
00841     struct sockaddr sa;
00842     struct sockaddr_in sin;
00843     struct sockaddr_in6 sin6;
00844   };
00845 
00846 /* Auxiliary function used by linux_xfer_osdata_isocket.  Formats
00847    information for all open internet sockets of type FAMILY on the
00848    system into BUFFER.  If TCP is set, only TCP sockets are processed,
00849    otherwise only UDP sockets are processed.  */
00850 
00851 static void
00852 print_sockets (unsigned short family, int tcp, struct buffer *buffer)
00853 {
00854   const char *proc_file;
00855   FILE *fp;
00856 
00857   if (family == AF_INET)
00858     proc_file = tcp ? "/proc/net/tcp" : "/proc/net/udp";
00859   else if (family == AF_INET6)
00860     proc_file = tcp ? "/proc/net/tcp6" : "/proc/net/udp6";
00861   else
00862     return;
00863 
00864   fp = gdb_fopen_cloexec (proc_file, "r");
00865   if (fp)
00866     {
00867       char buf[8192];
00868 
00869       do
00870         {
00871           if (fgets (buf, sizeof (buf), fp))
00872             {
00873               uid_t uid;
00874               unsigned long tlen, inode;
00875               int sl, timeout;
00876               unsigned int local_port, remote_port, state;
00877               unsigned int txq, rxq, trun, retn;
00878               char local_address[NI_MAXHOST], remote_address[NI_MAXHOST];
00879               char extra[512];
00880               int result;
00881 
00882               result = sscanf (buf,
00883                                "%d: %33[0-9A-F]:%X %33[0-9A-F]:%X %X %X:%X %X:%lX %X %d %d %lu %512s\n",
00884                                &sl,
00885                                local_address, &local_port,
00886                                remote_address, &remote_port,
00887                                &state,
00888                                &txq, &rxq,
00889                                &trun, &tlen,
00890                                &retn,
00891                                &uid,
00892                                &timeout,
00893                                &inode,
00894                                extra);
00895               
00896               if (result == 15)
00897                 {
00898                   union socket_addr locaddr, remaddr;
00899                   size_t addr_size;
00900                   char user[UT_NAMESIZE];
00901                   char local_service[NI_MAXSERV], remote_service[NI_MAXSERV];
00902 
00903                   if (family == AF_INET)
00904                     {
00905                       sscanf (local_address, "%X",
00906                               &locaddr.sin.sin_addr.s_addr);
00907                       sscanf (remote_address, "%X",
00908                               &remaddr.sin.sin_addr.s_addr);
00909                       
00910                       locaddr.sin.sin_port = htons (local_port);
00911                       remaddr.sin.sin_port = htons (remote_port);
00912 
00913                       addr_size = sizeof (struct sockaddr_in);
00914                     }
00915                   else
00916                     {
00917                       sscanf (local_address, "%8X%8X%8X%8X",
00918                               locaddr.sin6.sin6_addr.s6_addr32,
00919                               locaddr.sin6.sin6_addr.s6_addr32 + 1,
00920                               locaddr.sin6.sin6_addr.s6_addr32 + 2,
00921                               locaddr.sin6.sin6_addr.s6_addr32 + 3);
00922                       sscanf (remote_address, "%8X%8X%8X%8X",
00923                               remaddr.sin6.sin6_addr.s6_addr32,
00924                               remaddr.sin6.sin6_addr.s6_addr32 + 1,
00925                               remaddr.sin6.sin6_addr.s6_addr32 + 2,
00926                               remaddr.sin6.sin6_addr.s6_addr32 + 3);
00927 
00928                       locaddr.sin6.sin6_port = htons (local_port);
00929                       remaddr.sin6.sin6_port = htons (remote_port);
00930                       
00931                       locaddr.sin6.sin6_flowinfo = 0;
00932                       remaddr.sin6.sin6_flowinfo = 0;
00933                       locaddr.sin6.sin6_scope_id = 0;
00934                       remaddr.sin6.sin6_scope_id = 0;
00935 
00936                       addr_size = sizeof (struct sockaddr_in6);
00937                     }
00938               
00939                   locaddr.sa.sa_family = remaddr.sa.sa_family = family;
00940                       
00941                   result = getnameinfo (&locaddr.sa, addr_size,
00942                                         local_address, sizeof (local_address),
00943                                         local_service, sizeof (local_service),
00944                                         NI_NUMERICHOST | NI_NUMERICSERV
00945                                         | (tcp ? 0 : NI_DGRAM));
00946                   if (result)
00947                     continue;
00948                   
00949                   result = getnameinfo (&remaddr.sa, addr_size,
00950                                         remote_address,
00951                                         sizeof (remote_address),
00952                                         remote_service,
00953                                         sizeof (remote_service),
00954                                         NI_NUMERICHOST | NI_NUMERICSERV
00955                                         | (tcp ? 0 : NI_DGRAM));
00956                   if (result)
00957                     continue;
00958                   
00959                   user_from_uid (user, sizeof (user), uid);
00960                   
00961                   buffer_xml_printf (
00962                       buffer,
00963                       "<item>"
00964                       "<column name=\"local address\">%s</column>"
00965                       "<column name=\"local port\">%s</column>"
00966                       "<column name=\"remote address\">%s</column>"
00967                       "<column name=\"remote port\">%s</column>"
00968                       "<column name=\"state\">%s</column>"
00969                       "<column name=\"user\">%s</column>"
00970                       "<column name=\"family\">%s</column>" 
00971                       "<column name=\"protocol\">%s</column>"
00972                       "</item>",
00973                       local_address,
00974                       local_service,
00975                       remote_address,
00976                       remote_service,
00977                       format_socket_state (state),
00978                       user,
00979                       (family == AF_INET) ? "INET" : "INET6",
00980                       tcp ? "STREAM" : "DGRAM");
00981                 }
00982             }
00983         }
00984       while (!feof (fp));
00985 
00986       fclose (fp);
00987     }
00988 }
00989 
00990 /* Collect data about internet sockets and write it into READBUF.  */
00991 
00992 static LONGEST
00993 linux_xfer_osdata_isockets (gdb_byte *readbuf,
00994                             ULONGEST offset, LONGEST len)
00995 {
00996   static const char *buf;
00997   static LONGEST len_avail = -1;
00998   static struct buffer buffer;
00999 
01000   if (offset == 0)
01001     {
01002       if (len_avail != -1 && len_avail != 0)
01003         buffer_free (&buffer);
01004       len_avail = 0;
01005       buf = NULL;
01006       buffer_init (&buffer);
01007       buffer_grow_str (&buffer, "<osdata type=\"I sockets\">\n");
01008 
01009       print_sockets (AF_INET, 1, &buffer);
01010       print_sockets (AF_INET, 0, &buffer);
01011       print_sockets (AF_INET6, 1, &buffer);
01012       print_sockets (AF_INET6, 0, &buffer);
01013 
01014       buffer_grow_str0 (&buffer, "</osdata>\n");
01015       buf = buffer_finish (&buffer);
01016       len_avail = strlen (buf);
01017     }
01018 
01019   if (offset >= len_avail)
01020     {
01021       /* Done.  Get rid of the buffer.  */
01022       buffer_free (&buffer);
01023       buf = NULL;
01024       len_avail = 0;
01025       return 0;
01026     }
01027 
01028   if (len > len_avail - offset)
01029     len = len_avail - offset;
01030   memcpy (readbuf, buf + offset, len);
01031 
01032   return len;
01033 }
01034 
01035 /* Converts the time SECONDS into textual form and copies it into a
01036    buffer TIME, with at most MAXLEN characters copied.  */
01037 
01038 static void
01039 time_from_time_t (char *time, int maxlen, TIME_T seconds)
01040 {
01041   if (!seconds)
01042     time[0] = '\0';
01043   else
01044     {
01045       time_t t = (time_t) seconds;
01046       
01047       strncpy (time, ctime (&t), maxlen);
01048       time[maxlen - 1] = '\0';
01049     }
01050 }
01051 
01052 /* Finds the group name for the group GID and copies it into GROUP.
01053    At most MAXLEN characters are copied.  */
01054 
01055 static void
01056 group_from_gid (char *group, int maxlen, gid_t gid)
01057 {
01058   struct group *grentry = getgrgid (gid);
01059   
01060   if (grentry)
01061     {
01062       strncpy (group, grentry->gr_name, maxlen);
01063       /* Ensure that the group name is null-terminated.  */
01064       group[maxlen - 1] = '\0';
01065     }
01066   else
01067     group[0] = '\0';
01068 }
01069 
01070 /* Collect data about shared memory recorded in /proc and write it
01071    into READBUF.  */
01072 
01073 static LONGEST
01074 linux_xfer_osdata_shm (gdb_byte *readbuf,
01075                        ULONGEST offset, LONGEST len)
01076 {
01077   static const char *buf;
01078   static LONGEST len_avail = -1;
01079   static struct buffer buffer;
01080 
01081   if (offset == 0)
01082     {
01083       FILE *fp;
01084 
01085       if (len_avail != -1 && len_avail != 0)
01086         buffer_free (&buffer);
01087       len_avail = 0;
01088       buf = NULL;
01089       buffer_init (&buffer);
01090       buffer_grow_str (&buffer, "<osdata type=\"shared memory\">\n");
01091 
01092       fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
01093       if (fp)
01094         {
01095           char buf[8192];
01096 
01097           do
01098             {
01099               if (fgets (buf, sizeof (buf), fp))
01100                 {
01101                   key_t key;
01102                   uid_t uid, cuid;
01103                   gid_t gid, cgid;
01104                   PID_T cpid, lpid;
01105                   int shmid, size, nattch;
01106                   TIME_T atime, dtime, ctime;
01107                   unsigned int perms;
01108                   int items_read;
01109                                   
01110                   items_read = sscanf (buf,
01111                                        "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
01112                                        &key, &shmid, &perms, &size,
01113                                        &cpid, &lpid,
01114                                        &nattch,
01115                                        &uid, &gid, &cuid, &cgid,
01116                                        &atime, &dtime, &ctime);
01117 
01118                   if (items_read == 14)
01119                     {
01120                       char user[UT_NAMESIZE], group[UT_NAMESIZE];
01121                       char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
01122                       char ccmd[32], lcmd[32];
01123                       char atime_str[32], dtime_str[32], ctime_str[32];
01124                       
01125                       user_from_uid (user, sizeof (user), uid);
01126                       group_from_gid (group, sizeof (group), gid);
01127                       user_from_uid (cuser, sizeof (cuser), cuid);
01128                       group_from_gid (cgroup, sizeof (cgroup), cgid);
01129                       
01130                       command_from_pid (ccmd, sizeof (ccmd), cpid);
01131                       command_from_pid (lcmd, sizeof (lcmd), lpid);
01132                       
01133                       time_from_time_t (atime_str, sizeof (atime_str), atime);
01134                       time_from_time_t (dtime_str, sizeof (dtime_str), dtime);
01135                       time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
01136                       
01137                       buffer_xml_printf (
01138                           &buffer,
01139                           "<item>"
01140                           "<column name=\"key\">%d</column>"
01141                           "<column name=\"shmid\">%d</column>"
01142                           "<column name=\"permissions\">%o</column>"
01143                           "<column name=\"size\">%d</column>"
01144                           "<column name=\"creator command\">%s</column>"
01145                           "<column name=\"last op. command\">%s</column>"
01146                           "<column name=\"num attached\">%d</column>"
01147                           "<column name=\"user\">%s</column>"
01148                           "<column name=\"group\">%s</column>"
01149                           "<column name=\"creator user\">%s</column>"
01150                           "<column name=\"creator group\">%s</column>"
01151                           "<column name=\"last shmat() time\">%s</column>"
01152                           "<column name=\"last shmdt() time\">%s</column>"
01153                           "<column name=\"last shmctl() time\">%s</column>"
01154                           "</item>",
01155                           key,
01156                           shmid,
01157                           perms,
01158                           size,
01159                           ccmd,
01160                           lcmd,
01161                           nattch,
01162                           user,
01163                           group,
01164                           cuser,
01165                           cgroup,
01166                           atime_str,
01167                           dtime_str,
01168                           ctime_str);
01169                     }
01170                 }
01171             }
01172           while (!feof (fp));
01173 
01174           fclose (fp);
01175         }
01176       
01177       buffer_grow_str0 (&buffer, "</osdata>\n");
01178       buf = buffer_finish (&buffer);
01179       len_avail = strlen (buf);
01180     }
01181 
01182   if (offset >= len_avail)
01183     {
01184       /* Done.  Get rid of the buffer.  */
01185       buffer_free (&buffer);
01186       buf = NULL;
01187       len_avail = 0;
01188       return 0;
01189     }
01190 
01191   if (len > len_avail - offset)
01192     len = len_avail - offset;
01193   memcpy (readbuf, buf + offset, len);
01194 
01195   return len;
01196 }
01197 
01198 /* Collect data about semaphores recorded in /proc and write it
01199    into READBUF.  */
01200 
01201 static LONGEST
01202 linux_xfer_osdata_sem (gdb_byte *readbuf,
01203                        ULONGEST offset, LONGEST len)
01204 {
01205   static const char *buf;
01206   static LONGEST len_avail = -1;
01207   static struct buffer buffer;
01208 
01209   if (offset == 0)
01210     {
01211       FILE *fp;
01212       
01213       if (len_avail != -1 && len_avail != 0)
01214         buffer_free (&buffer);
01215       len_avail = 0;
01216       buf = NULL;
01217       buffer_init (&buffer);
01218       buffer_grow_str (&buffer, "<osdata type=\"semaphores\">\n");
01219 
01220       fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
01221       if (fp)
01222         {
01223           char buf[8192];
01224           
01225           do
01226             {
01227               if (fgets (buf, sizeof (buf), fp))
01228                 {
01229                   key_t key;
01230                   uid_t uid, cuid;
01231                   gid_t gid, cgid;
01232                   unsigned int perms, nsems;
01233                   int semid;
01234                   TIME_T otime, ctime;
01235                   int items_read;
01236                   
01237                   items_read = sscanf (buf,
01238                                        "%d %d %o %u %d %d %d %d %lld %lld",
01239                                        &key, &semid, &perms, &nsems,
01240                                        &uid, &gid, &cuid, &cgid,
01241                                        &otime, &ctime);
01242                   
01243                   if (items_read == 10)
01244                     {
01245                       char user[UT_NAMESIZE], group[UT_NAMESIZE];
01246                       char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
01247                       char otime_str[32], ctime_str[32];
01248                       
01249                       user_from_uid (user, sizeof (user), uid);
01250                       group_from_gid (group, sizeof (group), gid);
01251                       user_from_uid (cuser, sizeof (cuser), cuid);
01252                       group_from_gid (cgroup, sizeof (cgroup), cgid);
01253                       
01254                       time_from_time_t (otime_str, sizeof (otime_str), otime);
01255                       time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
01256                       
01257                       buffer_xml_printf (
01258                           &buffer,
01259                           "<item>"
01260                           "<column name=\"key\">%d</column>"
01261                           "<column name=\"semid\">%d</column>"
01262                           "<column name=\"permissions\">%o</column>"
01263                           "<column name=\"num semaphores\">%u</column>"
01264                           "<column name=\"user\">%s</column>"
01265                           "<column name=\"group\">%s</column>"
01266                           "<column name=\"creator user\">%s</column>"
01267                           "<column name=\"creator group\">%s</column>"
01268                           "<column name=\"last semop() time\">%s</column>"
01269                           "<column name=\"last semctl() time\">%s</column>"
01270                           "</item>",
01271                           key,
01272                           semid,
01273                           perms,
01274                           nsems,
01275                           user,
01276                           group,
01277                           cuser,
01278                           cgroup,
01279                           otime_str,
01280                           ctime_str);
01281                     }
01282                 }
01283             }
01284           while (!feof (fp));
01285 
01286           fclose (fp);
01287         }
01288 
01289       buffer_grow_str0 (&buffer, "</osdata>\n");
01290       buf = buffer_finish (&buffer);
01291       len_avail = strlen (buf);
01292     }
01293 
01294   if (offset >= len_avail)
01295     {
01296       /* Done.  Get rid of the buffer.  */
01297       buffer_free (&buffer);
01298       buf = NULL;
01299       len_avail = 0;
01300       return 0;
01301     }
01302 
01303   if (len > len_avail - offset)
01304     len = len_avail - offset;
01305   memcpy (readbuf, buf + offset, len);
01306 
01307   return len;
01308 }
01309 
01310 /* Collect data about message queues recorded in /proc and write it
01311    into READBUF.  */
01312 
01313 static LONGEST
01314 linux_xfer_osdata_msg (gdb_byte *readbuf,
01315                        ULONGEST offset, LONGEST len)
01316 {
01317   static const char *buf;
01318   static LONGEST len_avail = -1;
01319   static struct buffer buffer;
01320 
01321   if (offset == 0)
01322     {
01323       FILE *fp;
01324       
01325       if (len_avail != -1 && len_avail != 0)
01326         buffer_free (&buffer);
01327       len_avail = 0;
01328       buf = NULL;
01329       buffer_init (&buffer);
01330       buffer_grow_str (&buffer, "<osdata type=\"message queues\">\n");
01331       
01332       fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
01333       if (fp)
01334         {
01335           char buf[8192];
01336           
01337           do
01338             {
01339               if (fgets (buf, sizeof (buf), fp))
01340                 {
01341                   key_t key;
01342                   PID_T lspid, lrpid;
01343                   uid_t uid, cuid;
01344                   gid_t gid, cgid;
01345                   unsigned int perms, cbytes, qnum;
01346                   int msqid;
01347                   TIME_T stime, rtime, ctime;
01348                   int items_read;
01349                   
01350                   items_read = sscanf (buf,
01351                                        "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
01352                                        &key, &msqid, &perms, &cbytes, &qnum,
01353                                        &lspid, &lrpid, &uid, &gid, &cuid, &cgid,
01354                                        &stime, &rtime, &ctime);
01355                   
01356                   if (items_read == 14)
01357                     {
01358                       char user[UT_NAMESIZE], group[UT_NAMESIZE];
01359                       char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
01360                       char lscmd[32], lrcmd[32];
01361                       char stime_str[32], rtime_str[32], ctime_str[32];
01362                       
01363                       user_from_uid (user, sizeof (user), uid);
01364                       group_from_gid (group, sizeof (group), gid);
01365                       user_from_uid (cuser, sizeof (cuser), cuid);
01366                       group_from_gid (cgroup, sizeof (cgroup), cgid);
01367                       
01368                       command_from_pid (lscmd, sizeof (lscmd), lspid);
01369                       command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
01370                       
01371                       time_from_time_t (stime_str, sizeof (stime_str), stime);
01372                       time_from_time_t (rtime_str, sizeof (rtime_str), rtime);
01373                       time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
01374                       
01375                       buffer_xml_printf (
01376                           &buffer,
01377                           "<item>"
01378                           "<column name=\"key\">%d</column>"
01379                           "<column name=\"msqid\">%d</column>"
01380                           "<column name=\"permissions\">%o</column>"
01381                           "<column name=\"num used bytes\">%u</column>"
01382                           "<column name=\"num messages\">%u</column>"
01383                           "<column name=\"last msgsnd() command\">%s</column>"
01384                           "<column name=\"last msgrcv() command\">%s</column>"
01385                           "<column name=\"user\">%s</column>"
01386                           "<column name=\"group\">%s</column>"
01387                           "<column name=\"creator user\">%s</column>"
01388                           "<column name=\"creator group\">%s</column>"
01389                           "<column name=\"last msgsnd() time\">%s</column>"
01390                           "<column name=\"last msgrcv() time\">%s</column>"
01391                           "<column name=\"last msgctl() time\">%s</column>"
01392                           "</item>",
01393                           key,
01394                           msqid,
01395                           perms,
01396                           cbytes,
01397                           qnum,
01398                           lscmd,
01399                           lrcmd,
01400                           user,
01401                           group,
01402                           cuser,
01403                           cgroup,
01404                           stime_str,
01405                           rtime_str,
01406                           ctime_str);
01407                     }
01408                 }
01409             }
01410           while (!feof (fp));
01411 
01412           fclose (fp);
01413         }
01414 
01415       buffer_grow_str0 (&buffer, "</osdata>\n");
01416       buf = buffer_finish (&buffer);
01417       len_avail = strlen (buf);
01418     }
01419 
01420   if (offset >= len_avail)
01421     {
01422       /* Done.  Get rid of the buffer.  */
01423       buffer_free (&buffer);
01424       buf = NULL;
01425       len_avail = 0;
01426       return 0;
01427     }
01428 
01429   if (len > len_avail - offset)
01430     len = len_avail - offset;
01431   memcpy (readbuf, buf + offset, len);
01432 
01433   return len;
01434 }
01435 
01436 /* Collect data about loaded kernel modules and write it into
01437    READBUF.  */
01438 
01439 static LONGEST
01440 linux_xfer_osdata_modules (gdb_byte *readbuf,
01441                            ULONGEST offset, LONGEST len)
01442 {
01443   static const char *buf;
01444   static LONGEST len_avail = -1;
01445   static struct buffer buffer;
01446 
01447   if (offset == 0)
01448     {
01449       FILE *fp;
01450 
01451       if (len_avail != -1 && len_avail != 0)
01452         buffer_free (&buffer);
01453       len_avail = 0;
01454       buf = NULL;
01455       buffer_init (&buffer);
01456       buffer_grow_str (&buffer, "<osdata type=\"modules\">\n");
01457 
01458       fp = gdb_fopen_cloexec ("/proc/modules", "r");
01459       if (fp)
01460         {
01461           char buf[8192];
01462           
01463           do
01464             {
01465               if (fgets (buf, sizeof (buf), fp))
01466                 {
01467                   char name[64], dependencies[256], status[16];
01468                   unsigned int size;
01469                   unsigned long long address;
01470                   int uses;
01471                   int items_read;
01472                   
01473                   items_read = sscanf (buf,
01474                                        "%64s %d %d %256s %16s 0x%llx",
01475                                        name, &size, &uses,
01476                                        dependencies, status, &address);
01477 
01478                   if (items_read == 6)
01479                     buffer_xml_printf (
01480                         &buffer,
01481                         "<item>"
01482                         "<column name=\"name\">%s</column>"
01483                         "<column name=\"size\">%u</column>"
01484                         "<column name=\"num uses\">%d</column>"
01485                         "<column name=\"dependencies\">%s</column>"
01486                         "<column name=\"status\">%s</column>"
01487                         "<column name=\"address\">%llx</column>"
01488                         "</item>",
01489                         name,
01490                         size,
01491                         uses,
01492                         dependencies,
01493                         status,
01494                         address);
01495                 }
01496             }
01497           while (!feof (fp));
01498 
01499           fclose (fp);
01500         }
01501 
01502       buffer_grow_str0 (&buffer, "</osdata>\n");
01503       buf = buffer_finish (&buffer);
01504       len_avail = strlen (buf);
01505     }
01506 
01507   if (offset >= len_avail)
01508     {
01509       /* Done.  Get rid of the buffer.  */
01510       buffer_free (&buffer);
01511       buf = NULL;
01512       len_avail = 0;
01513       return 0;
01514     }
01515 
01516   if (len > len_avail - offset)
01517     len = len_avail - offset;
01518   memcpy (readbuf, buf + offset, len);
01519 
01520   return len;
01521 }
01522 
01523 struct osdata_type {
01524   char *type;
01525   char *title;
01526   char *description;
01527   LONGEST (*getter) (gdb_byte *readbuf, ULONGEST offset, LONGEST len);
01528 } osdata_table[] = {
01529   { "processes", "Processes", "Listing of all processes",
01530     linux_xfer_osdata_processes },
01531   { "procgroups", "Process groups", "Listing of all process groups",
01532     linux_xfer_osdata_processgroups },
01533   { "threads", "Threads", "Listing of all threads",
01534     linux_xfer_osdata_threads },
01535   { "files", "File descriptors", "Listing of all file descriptors",
01536     linux_xfer_osdata_fds },
01537   { "sockets", "Sockets", "Listing of all internet-domain sockets",
01538     linux_xfer_osdata_isockets },
01539   { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
01540     linux_xfer_osdata_shm },
01541   { "semaphores", "Semaphores", "Listing of all semaphores",
01542     linux_xfer_osdata_sem },
01543   { "msg", "Message queues", "Listing of all message queues",
01544     linux_xfer_osdata_msg },
01545   { "modules", "Kernel modules", "Listing of all loaded kernel modules",
01546     linux_xfer_osdata_modules },
01547   { NULL, NULL, NULL }
01548 };
01549 
01550 LONGEST
01551 linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
01552                           ULONGEST offset, LONGEST len)
01553 {
01554   if (!annex || *annex == '\0')
01555     {
01556       static const char *buf;
01557       static LONGEST len_avail = -1;
01558       static struct buffer buffer;
01559 
01560       if (offset == 0)
01561         {
01562           int i;
01563 
01564           if (len_avail != -1 && len_avail != 0)
01565             buffer_free (&buffer);
01566           len_avail = 0;
01567           buf = NULL;
01568           buffer_init (&buffer);
01569           buffer_grow_str (&buffer, "<osdata type=\"types\">\n");
01570 
01571           for (i = 0; osdata_table[i].type; ++i)
01572             buffer_xml_printf (
01573                                &buffer,
01574                                "<item>"
01575                                "<column name=\"Type\">%s</column>"
01576                                "<column name=\"Description\">%s</column>"
01577                                "<column name=\"Title\">%s</column>"
01578                                "</item>",
01579                                osdata_table[i].type,
01580                                osdata_table[i].description,
01581                                osdata_table[i].title);
01582 
01583           buffer_grow_str0 (&buffer, "</osdata>\n");
01584           buf = buffer_finish (&buffer);
01585           len_avail = strlen (buf);
01586         }
01587 
01588       if (offset >= len_avail)
01589         {
01590           /* Done.  Get rid of the buffer.  */
01591           buffer_free (&buffer);
01592           buf = NULL;
01593           len_avail = 0;
01594           return 0;
01595         }
01596 
01597       if (len > len_avail - offset)
01598         len = len_avail - offset;
01599       memcpy (readbuf, buf + offset, len);
01600 
01601       return len;
01602     }
01603   else
01604     {
01605       int i;
01606 
01607       for (i = 0; osdata_table[i].type; ++i)
01608         {
01609           if (strcmp (annex, osdata_table[i].type) == 0)
01610             {
01611               gdb_assert (readbuf);
01612               
01613               return (osdata_table[i].getter) (readbuf, offset, len);
01614             }
01615         }
01616 
01617       return 0;
01618     }
01619 }
01620 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines