xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/nat/linux-osdata.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /* Linux-specific functions to retrieve OS data.
2 
3    Copyright (C) 2009-2023 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "gdbsupport/common-defs.h"
21 #include "linux-osdata.h"
22 
23 #include <sys/types.h>
24 #include <sys/sysinfo.h>
25 #include <ctype.h>
26 #include <utmp.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <pwd.h>
30 #include <grp.h>
31 #include <netdb.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 
35 #include "gdbsupport/xml-utils.h"
36 #include "gdbsupport/buffer.h"
37 #include <dirent.h>
38 #include <sys/stat.h>
39 #include "gdbsupport/filestuff.h"
40 #include <algorithm>
41 
42 #define NAMELEN(dirent) strlen ((dirent)->d_name)
43 
44 /* Define PID_T to be a fixed size that is at least as large as pid_t,
45    so that reading pid values embedded in /proc works
46    consistently.  */
47 
48 typedef long long  PID_T;
49 
50 /* Define TIME_T to be at least as large as time_t, so that reading
51    time values embedded in /proc works consistently.  */
52 
53 typedef long long TIME_T;
54 
55 #define MAX_PID_T_STRLEN  (sizeof ("-9223372036854775808") - 1)
56 
57 /* Returns the CPU core that thread PTID is currently running on.  */
58 
59 /* Compute and return the processor core of a given thread.  */
60 
61 int
62 linux_common_core_of_thread (ptid_t ptid)
63 {
64   char filename[sizeof ("/proc//task//stat") + 2 * MAX_PID_T_STRLEN];
65   int core;
66 
67   sprintf (filename, "/proc/%lld/task/%lld/stat",
68 	   (PID_T) ptid.pid (), (PID_T) ptid.lwp ());
69 
70   gdb::optional<std::string> content = read_text_file_to_string (filename);
71   if (!content.has_value ())
72     return -1;
73 
74   /* ps command also relies on no trailing fields ever contain ')'.  */
75   std::string::size_type pos = content->find_last_of (')');
76   if (pos == std::string::npos)
77     return -1;
78 
79   /* If the first field after program name has index 0, then core number is
80      the field with index 36 (so, the 37th).  There's no constant for that
81      anywhere.  */
82   for (int i = 0; i < 37; ++i)
83     {
84       /* Find separator.  */
85       pos = content->find_first_of (' ', pos);
86       if (pos == std::string::npos)
87 	return {};
88 
89       /* Find beginning of field.  */
90       pos = content->find_first_not_of (' ', pos);
91       if (pos == std::string::npos)
92 	return {};
93     }
94 
95   if (sscanf (&(*content)[pos], "%d", &core) == 0)
96     core = -1;
97 
98   return core;
99 }
100 
101 /* Finds the command-line of process PID and copies it into COMMAND.
102    At most MAXLEN characters are copied.  If the command-line cannot
103    be found, PID is copied into command in text-form.  */
104 
105 static void
106 command_from_pid (char *command, int maxlen, PID_T pid)
107 {
108   std::string stat_path = string_printf ("/proc/%lld/stat", pid);
109   gdb_file_up fp = gdb_fopen_cloexec (stat_path, "r");
110 
111   command[0] = '\0';
112 
113   if (fp)
114     {
115       /* sizeof (cmd) should be greater or equal to TASK_COMM_LEN (in
116 	 include/linux/sched.h in the Linux kernel sources) plus two
117 	 (for the brackets).  */
118       char cmd[18];
119       PID_T stat_pid;
120       int items_read = fscanf (fp.get (), "%lld %17s", &stat_pid, cmd);
121 
122       if (items_read == 2 && pid == stat_pid)
123 	{
124 	  cmd[strlen (cmd) - 1] = '\0'; /* Remove trailing parenthesis.  */
125 	  strncpy (command, cmd + 1, maxlen); /* Ignore leading parenthesis.  */
126 	}
127     }
128   else
129     {
130       /* Return the PID if a /proc entry for the process cannot be found.  */
131       snprintf (command, maxlen, "%lld", pid);
132     }
133 
134   command[maxlen - 1] = '\0'; /* Ensure string is null-terminated.  */
135 }
136 
137 /* Returns the command-line of the process with the given PID. The
138    returned string needs to be freed using xfree after use.  */
139 
140 static char *
141 commandline_from_pid (PID_T pid)
142 {
143   std::string pathname = string_printf ("/proc/%lld/cmdline", pid);
144   char *commandline = NULL;
145   gdb_file_up f = gdb_fopen_cloexec (pathname, "r");
146 
147   if (f)
148     {
149       size_t len = 0;
150 
151       while (!feof (f.get ()))
152 	{
153 	  char buf[1024];
154 	  size_t read_bytes = fread (buf, 1, sizeof (buf), f.get ());
155 
156 	  if (read_bytes)
157 	    {
158 	      commandline = (char *) xrealloc (commandline, len + read_bytes + 1);
159 	      memcpy (commandline + len, buf, read_bytes);
160 	      len += read_bytes;
161 	    }
162 	}
163 
164       if (commandline)
165 	{
166 	  size_t i;
167 
168 	  /* Replace null characters with spaces.  */
169 	  for (i = 0; i < len; ++i)
170 	    if (commandline[i] == '\0')
171 	      commandline[i] = ' ';
172 
173 	  commandline[len] = '\0';
174 	}
175       else
176 	{
177 	  /* Return the command in square brackets if the command-line
178 	     is empty.  */
179 	  commandline = (char *) xmalloc (32);
180 	  commandline[0] = '[';
181 	  command_from_pid (commandline + 1, 31, pid);
182 
183 	  len = strlen (commandline);
184 	  if (len < 31)
185 	    strcat (commandline, "]");
186 	}
187     }
188 
189   return commandline;
190 }
191 
192 /* Finds the user name for the user UID and copies it into USER.  At
193    most MAXLEN characters are copied.  */
194 
195 static void
196 user_from_uid (char *user, int maxlen, uid_t uid)
197 {
198   struct passwd *pwentry;
199   char buf[1024];
200   struct passwd pwd;
201   getpwuid_r (uid, &pwd, buf, sizeof (buf), &pwentry);
202 
203   if (pwentry)
204     {
205       strncpy (user, pwentry->pw_name, maxlen - 1);
206       /* Ensure that the user name is null-terminated.  */
207       user[maxlen - 1] = '\0';
208     }
209   else
210     user[0] = '\0';
211 }
212 
213 /* Finds the owner of process PID and returns the user id in OWNER.
214    Returns 0 if the owner was found, -1 otherwise.  */
215 
216 static int
217 get_process_owner (uid_t *owner, PID_T pid)
218 {
219   struct stat statbuf;
220   char procentry[sizeof ("/proc/") + MAX_PID_T_STRLEN];
221 
222   sprintf (procentry, "/proc/%lld", pid);
223 
224   if (stat (procentry, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
225     {
226       *owner = statbuf.st_uid;
227       return 0;
228     }
229   else
230     return -1;
231 }
232 
233 /* Find the CPU cores used by process PID and return them in CORES.
234    CORES points to an array of NUM_CORES elements.  */
235 
236 static int
237 get_cores_used_by_process (PID_T pid, int *cores, const int num_cores)
238 {
239   char taskdir[sizeof ("/proc/") + MAX_PID_T_STRLEN + sizeof ("/task") - 1];
240   DIR *dir;
241   struct dirent *dp;
242   int task_count = 0;
243 
244   sprintf (taskdir, "/proc/%lld/task", pid);
245   dir = opendir (taskdir);
246   if (dir)
247     {
248       while ((dp = readdir (dir)) != NULL)
249 	{
250 	  PID_T tid;
251 	  int core;
252 
253 	  if (!isdigit (dp->d_name[0])
254 	      || NAMELEN (dp) > MAX_PID_T_STRLEN)
255 	    continue;
256 
257 	  sscanf (dp->d_name, "%lld", &tid);
258 	  core = linux_common_core_of_thread (ptid_t ((pid_t) pid,
259 						      (pid_t) tid));
260 
261 	  if (core >= 0 && core < num_cores)
262 	    {
263 	      ++cores[core];
264 	      ++task_count;
265 	    }
266 	}
267 
268       closedir (dir);
269     }
270 
271   return task_count;
272 }
273 
274 /* get_core_array_size helper that uses /sys/devices/system/cpu/possible.  */
275 
276 static gdb::optional<size_t>
277 get_core_array_size_using_sys_possible ()
278 {
279   gdb::optional<std::string> possible
280     = read_text_file_to_string ("/sys/devices/system/cpu/possible");
281 
282   if (!possible.has_value ())
283     return {};
284 
285   /* The format is documented here:
286 
287        https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst
288 
289      For the purpose of this function, we assume the file can contain a complex
290      set of ranges, like `2,4-31,32-63`.  Read all number, disregarding commands
291      and dashes, in order to find the largest possible core number.  The size
292      of the array to allocate is that plus one.  */
293 
294   unsigned long max_id = 0;
295   for (std::string::size_type start = 0; start < possible->size ();)
296     {
297       const char *start_p = &(*possible)[start];
298       char *end_p;
299 
300       /* Parse one number.  */
301       errno = 0;
302       unsigned long id = strtoul (start_p, &end_p, 10);
303       if (errno != 0)
304 	return {};
305 
306       max_id = std::max (max_id, id);
307 
308       start += end_p - start_p;
309       gdb_assert (start <= possible->size ());
310 
311       /* Skip comma, dash, or new line (if we are at the end).  */
312       ++start;
313     }
314 
315   return max_id + 1;
316 }
317 
318 /* Return the array size to allocate in order to be able to index it using
319    CPU core numbers.  This may be more than the actual number of cores if
320    the core numbers are not contiguous.  */
321 
322 static size_t
323 get_core_array_size ()
324 {
325   /* Using /sys/.../possible is prefered, because it handles the case where
326      we are in a container that has access to a subset of the host's cores.
327      It will return a size that considers all the CPU cores available to the
328      host.  If that fials for some reason, fall back to sysconf.  */
329   gdb::optional<size_t> count = get_core_array_size_using_sys_possible ();
330   if (count.has_value ())
331     return *count;
332 
333   return sysconf (_SC_NPROCESSORS_ONLN);
334 }
335 
336 static std::string
337 linux_xfer_osdata_processes ()
338 {
339   DIR *dirp;
340   std::string buffer = "<osdata type=\"processes\">\n";
341 
342   dirp = opendir ("/proc");
343   if (dirp)
344     {
345       const int core_array_size = get_core_array_size ();
346       struct dirent *dp;
347 
348       while ((dp = readdir (dirp)) != NULL)
349 	{
350 	  PID_T pid;
351 	  uid_t owner;
352 	  char user[UT_NAMESIZE];
353 	  char *command_line;
354 	  int *cores;
355 	  int task_count;
356 	  std::string cores_str;
357 	  int i;
358 
359 	  if (!isdigit (dp->d_name[0])
360 	      || NAMELEN (dp) > MAX_PID_T_STRLEN)
361 	    continue;
362 
363 	  sscanf (dp->d_name, "%lld", &pid);
364 	  command_line = commandline_from_pid (pid);
365 
366 	  if (get_process_owner (&owner, pid) == 0)
367 	    user_from_uid (user, sizeof (user), owner);
368 	  else
369 	    strcpy (user, "?");
370 
371 	  /* Find CPU cores used by the process.  */
372 	  cores = XCNEWVEC (int, core_array_size);
373 	  task_count = get_cores_used_by_process (pid, cores, core_array_size);
374 
375 	  for (i = 0; i < core_array_size && task_count > 0; ++i)
376 	    if (cores[i])
377 	      {
378 		string_appendf (cores_str, "%d", i);
379 
380 		task_count -= cores[i];
381 		if (task_count > 0)
382 		  cores_str += ",";
383 	      }
384 
385 	  xfree (cores);
386 
387 	  string_xml_appendf
388 	    (buffer,
389 	     "<item>"
390 	     "<column name=\"pid\">%lld</column>"
391 	     "<column name=\"user\">%s</column>"
392 	     "<column name=\"command\">%s</column>"
393 	     "<column name=\"cores\">%s</column>"
394 	     "</item>",
395 	     pid,
396 	     user,
397 	     command_line ? command_line : "",
398 	     cores_str.c_str());
399 
400 	  xfree (command_line);
401 	}
402 
403       closedir (dirp);
404     }
405 
406   buffer += "</osdata>\n";
407 
408   return buffer;
409 }
410 
411 /* A simple PID/PGID pair.  */
412 
413 struct pid_pgid_entry
414 {
415   pid_pgid_entry (PID_T pid_, PID_T pgid_)
416   : pid (pid_), pgid (pgid_)
417   {}
418 
419   /* Return true if this pid is the leader of its process group.  */
420 
421   bool is_leader () const
422   {
423     return pid == pgid;
424   }
425 
426   bool operator< (const pid_pgid_entry &other) const
427   {
428     /* Sort by PGID.  */
429     if (this->pgid != other.pgid)
430       return this->pgid < other.pgid;
431 
432     /* Process group leaders always come first...  */
433     if (this->is_leader ())
434       {
435 	if (!other.is_leader ())
436 	  return true;
437       }
438     else if (other.is_leader ())
439       return false;
440 
441     /* ...else sort by PID.  */
442     return this->pid < other.pid;
443   }
444 
445   PID_T pid, pgid;
446 };
447 
448 /* Collect all process groups from /proc in BUFFER.  */
449 
450 static std::string
451 linux_xfer_osdata_processgroups ()
452 {
453   DIR *dirp;
454   std::string buffer = "<osdata type=\"process groups\">\n";
455 
456   dirp = opendir ("/proc");
457   if (dirp)
458     {
459       std::vector<pid_pgid_entry> process_list;
460       struct dirent *dp;
461 
462       process_list.reserve (512);
463 
464       /* Build list consisting of PIDs followed by their
465 	 associated PGID.  */
466       while ((dp = readdir (dirp)) != NULL)
467 	{
468 	  PID_T pid, pgid;
469 
470 	  if (!isdigit (dp->d_name[0])
471 	      || NAMELEN (dp) > MAX_PID_T_STRLEN)
472 	    continue;
473 
474 	  sscanf (dp->d_name, "%lld", &pid);
475 	  pgid = getpgid (pid);
476 
477 	  if (pgid > 0)
478 	    process_list.emplace_back (pid, pgid);
479 	}
480 
481       closedir (dirp);
482 
483       /* Sort the process list.  */
484       std::sort (process_list.begin (), process_list.end ());
485 
486       for (const pid_pgid_entry &entry : process_list)
487 	{
488 	  PID_T pid = entry.pid;
489 	  PID_T pgid = entry.pgid;
490 	  char leader_command[32];
491 	  char *command_line;
492 
493 	  command_from_pid (leader_command, sizeof (leader_command), pgid);
494 	  command_line = commandline_from_pid (pid);
495 
496 	  string_xml_appendf
497 	    (buffer,
498 	     "<item>"
499 	     "<column name=\"pgid\">%lld</column>"
500 	     "<column name=\"leader command\">%s</column>"
501 	     "<column name=\"pid\">%lld</column>"
502 	     "<column name=\"command line\">%s</column>"
503 	     "</item>",
504 	     pgid,
505 	     leader_command,
506 	     pid,
507 	     command_line ? command_line : "");
508 
509 	  xfree (command_line);
510 	}
511     }
512 
513   buffer += "</osdata>\n";
514 
515   return buffer;
516 }
517 
518 /* Collect all the threads in /proc by iterating through processes and
519    then tasks within each process.  */
520 
521 static std::string
522 linux_xfer_osdata_threads ()
523 {
524   DIR *dirp;
525   std::string buffer = "<osdata type=\"threads\">\n";
526 
527   dirp = opendir ("/proc");
528   if (dirp)
529     {
530       struct dirent *dp;
531 
532       while ((dp = readdir (dirp)) != NULL)
533 	{
534 	  struct stat statbuf;
535 	  char procentry[sizeof ("/proc/4294967295")];
536 
537 	  if (!isdigit (dp->d_name[0])
538 	      || NAMELEN (dp) > sizeof ("4294967295") - 1)
539 	    continue;
540 
541 	  xsnprintf (procentry, sizeof (procentry), "/proc/%s",
542 		     dp->d_name);
543 	  if (stat (procentry, &statbuf) == 0
544 	      && S_ISDIR (statbuf.st_mode))
545 	    {
546 	      DIR *dirp2;
547 	      PID_T pid;
548 	      char command[32];
549 
550 	      std::string pathname
551 		= string_printf ("/proc/%s/task", dp->d_name);
552 
553 	      pid = atoi (dp->d_name);
554 	      command_from_pid (command, sizeof (command), pid);
555 
556 	      dirp2 = opendir (pathname.c_str ());
557 
558 	      if (dirp2)
559 		{
560 		  struct dirent *dp2;
561 
562 		  while ((dp2 = readdir (dirp2)) != NULL)
563 		    {
564 		      PID_T tid;
565 		      int core;
566 
567 		      if (!isdigit (dp2->d_name[0])
568 			  || NAMELEN (dp2) > sizeof ("4294967295") - 1)
569 			continue;
570 
571 		      tid = atoi (dp2->d_name);
572 		      core = linux_common_core_of_thread (ptid_t (pid, tid));
573 
574 		      string_xml_appendf
575 			(buffer,
576 			 "<item>"
577 			 "<column name=\"pid\">%lld</column>"
578 			 "<column name=\"command\">%s</column>"
579 			 "<column name=\"tid\">%lld</column>"
580 			 "<column name=\"core\">%d</column>"
581 			 "</item>",
582 			 pid,
583 			 command,
584 			 tid,
585 			 core);
586 		    }
587 
588 		  closedir (dirp2);
589 		}
590 	    }
591 	}
592 
593       closedir (dirp);
594     }
595 
596   buffer += "</osdata>\n";
597 
598   return buffer;
599 }
600 
601 /* Collect data about the cpus/cores on the system in BUFFER.  */
602 
603 static std::string
604 linux_xfer_osdata_cpus ()
605 {
606   int first_item = 1;
607   std::string buffer = "<osdata type=\"cpus\">\n";
608 
609   gdb_file_up fp = gdb_fopen_cloexec ("/proc/cpuinfo", "r");
610   if (fp != NULL)
611     {
612       char buf[8192];
613 
614       do
615 	{
616 	  if (fgets (buf, sizeof (buf), fp.get ()))
617 	    {
618 	      char *key, *value;
619 	      int i = 0;
620 
621 	      char *saveptr;
622 	      key = strtok_r (buf, ":", &saveptr);
623 	      if (key == NULL)
624 		continue;
625 
626 	      value = strtok_r (NULL, ":", &saveptr);
627 	      if (value == NULL)
628 		continue;
629 
630 	      while (key[i] != '\t' && key[i] != '\0')
631 		i++;
632 
633 	      key[i] = '\0';
634 
635 	      i = 0;
636 	      while (value[i] != '\t' && value[i] != '\0')
637 		i++;
638 
639 	      value[i] = '\0';
640 
641 	      if (strcmp (key, "processor") == 0)
642 		{
643 		  if (first_item)
644 		    buffer += "<item>";
645 		  else
646 		    buffer += "</item><item>";
647 
648 		  first_item = 0;
649 		}
650 
651 	      string_xml_appendf (buffer,
652 				  "<column name=\"%s\">%s</column>",
653 				  key,
654 				  value);
655 	    }
656 	}
657       while (!feof (fp.get ()));
658 
659       if (first_item == 0)
660 	buffer += "</item>";
661     }
662 
663   buffer += "</osdata>\n";
664 
665   return buffer;
666 }
667 
668 /* Collect all the open file descriptors found in /proc and put the details
669    found about them into BUFFER.  */
670 
671 static std::string
672 linux_xfer_osdata_fds ()
673 {
674   DIR *dirp;
675   std::string buffer = "<osdata type=\"files\">\n";
676 
677   dirp = opendir ("/proc");
678   if (dirp)
679     {
680       struct dirent *dp;
681 
682       while ((dp = readdir (dirp)) != NULL)
683 	{
684 	  struct stat statbuf;
685 	  char procentry[sizeof ("/proc/4294967295")];
686 
687 	  if (!isdigit (dp->d_name[0])
688 	      || NAMELEN (dp) > sizeof ("4294967295") - 1)
689 	    continue;
690 
691 	  xsnprintf (procentry, sizeof (procentry), "/proc/%s",
692 		     dp->d_name);
693 	  if (stat (procentry, &statbuf) == 0
694 	      && S_ISDIR (statbuf.st_mode))
695 	    {
696 	      DIR *dirp2;
697 	      PID_T pid;
698 	      char command[32];
699 
700 	      pid = atoi (dp->d_name);
701 	      command_from_pid (command, sizeof (command), pid);
702 
703 	      std::string pathname
704 		= string_printf ("/proc/%s/fd", dp->d_name);
705 	      dirp2 = opendir (pathname.c_str ());
706 
707 	      if (dirp2)
708 		{
709 		  struct dirent *dp2;
710 
711 		  while ((dp2 = readdir (dirp2)) != NULL)
712 		    {
713 		      char buf[1000];
714 		      ssize_t rslt;
715 
716 		      if (!isdigit (dp2->d_name[0]))
717 			continue;
718 
719 		      std::string fdname
720 			= string_printf ("%s/%s", pathname.c_str (),
721 					 dp2->d_name);
722 		      rslt = readlink (fdname.c_str (), buf,
723 				       sizeof (buf) - 1);
724 		      if (rslt >= 0)
725 			buf[rslt] = '\0';
726 
727 		      string_xml_appendf
728 			(buffer,
729 			 "<item>"
730 			 "<column name=\"pid\">%s</column>"
731 			 "<column name=\"command\">%s</column>"
732 			 "<column name=\"file descriptor\">%s</column>"
733 			 "<column name=\"name\">%s</column>"
734 			 "</item>",
735 			 dp->d_name,
736 			 command,
737 			 dp2->d_name,
738 			 (rslt >= 0 ? buf : dp2->d_name));
739 		    }
740 
741 		  closedir (dirp2);
742 		}
743 	    }
744 	}
745 
746       closedir (dirp);
747     }
748 
749   buffer += "</osdata>\n";
750 
751   return buffer;
752 }
753 
754 /* Returns the socket state STATE in textual form.  */
755 
756 static const char *
757 format_socket_state (unsigned char state)
758 {
759   /* Copied from include/net/tcp_states.h in the Linux kernel sources.  */
760   enum {
761     TCP_ESTABLISHED = 1,
762     TCP_SYN_SENT,
763     TCP_SYN_RECV,
764     TCP_FIN_WAIT1,
765     TCP_FIN_WAIT2,
766     TCP_TIME_WAIT,
767     TCP_CLOSE,
768     TCP_CLOSE_WAIT,
769     TCP_LAST_ACK,
770     TCP_LISTEN,
771     TCP_CLOSING
772   };
773 
774   switch (state)
775     {
776     case TCP_ESTABLISHED:
777       return "ESTABLISHED";
778     case TCP_SYN_SENT:
779       return "SYN_SENT";
780     case TCP_SYN_RECV:
781       return "SYN_RECV";
782     case TCP_FIN_WAIT1:
783       return "FIN_WAIT1";
784     case TCP_FIN_WAIT2:
785       return "FIN_WAIT2";
786     case TCP_TIME_WAIT:
787       return "TIME_WAIT";
788     case TCP_CLOSE:
789       return "CLOSE";
790     case TCP_CLOSE_WAIT:
791       return "CLOSE_WAIT";
792     case TCP_LAST_ACK:
793       return "LAST_ACK";
794     case TCP_LISTEN:
795       return "LISTEN";
796     case TCP_CLOSING:
797       return "CLOSING";
798     default:
799       return "(unknown)";
800     }
801 }
802 
803 union socket_addr
804   {
805     struct sockaddr sa;
806     struct sockaddr_in sin;
807     struct sockaddr_in6 sin6;
808   };
809 
810 /* Auxiliary function used by linux_xfer_osdata_isocket.  Formats
811    information for all open internet sockets of type FAMILY on the
812    system into BUFFER.  If TCP is set, only TCP sockets are processed,
813    otherwise only UDP sockets are processed.  */
814 
815 static void
816 print_sockets (unsigned short family, int tcp, std::string &buffer)
817 {
818   const char *proc_file;
819 
820   if (family == AF_INET)
821     proc_file = tcp ? "/proc/net/tcp" : "/proc/net/udp";
822   else if (family == AF_INET6)
823     proc_file = tcp ? "/proc/net/tcp6" : "/proc/net/udp6";
824   else
825     return;
826 
827   gdb_file_up fp = gdb_fopen_cloexec (proc_file, "r");
828   if (fp)
829     {
830       char buf[8192];
831 
832       do
833 	{
834 	  if (fgets (buf, sizeof (buf), fp.get ()))
835 	    {
836 	      uid_t uid;
837 	      unsigned int local_port, remote_port, state;
838 	      char local_address[NI_MAXHOST], remote_address[NI_MAXHOST];
839 	      int result;
840 
841 #if NI_MAXHOST <= 32
842 #error "local_address and remote_address buffers too small"
843 #endif
844 
845 	      result = sscanf (buf,
846 			       "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
847 			       local_address, &local_port,
848 			       remote_address, &remote_port,
849 			       &state,
850 			       &uid);
851 
852 	      if (result == 6)
853 		{
854 		  union socket_addr locaddr, remaddr;
855 		  size_t addr_size;
856 		  char user[UT_NAMESIZE];
857 		  char local_service[NI_MAXSERV], remote_service[NI_MAXSERV];
858 
859 		  if (family == AF_INET)
860 		    {
861 		      sscanf (local_address, "%X",
862 			      &locaddr.sin.sin_addr.s_addr);
863 		      sscanf (remote_address, "%X",
864 			      &remaddr.sin.sin_addr.s_addr);
865 
866 		      locaddr.sin.sin_port = htons (local_port);
867 		      remaddr.sin.sin_port = htons (remote_port);
868 
869 		      addr_size = sizeof (struct sockaddr_in);
870 		    }
871 		  else
872 		    {
873 		      sscanf (local_address, "%8X%8X%8X%8X",
874 			      locaddr.sin6.sin6_addr.s6_addr32,
875 			      locaddr.sin6.sin6_addr.s6_addr32 + 1,
876 			      locaddr.sin6.sin6_addr.s6_addr32 + 2,
877 			      locaddr.sin6.sin6_addr.s6_addr32 + 3);
878 		      sscanf (remote_address, "%8X%8X%8X%8X",
879 			      remaddr.sin6.sin6_addr.s6_addr32,
880 			      remaddr.sin6.sin6_addr.s6_addr32 + 1,
881 			      remaddr.sin6.sin6_addr.s6_addr32 + 2,
882 			      remaddr.sin6.sin6_addr.s6_addr32 + 3);
883 
884 		      locaddr.sin6.sin6_port = htons (local_port);
885 		      remaddr.sin6.sin6_port = htons (remote_port);
886 
887 		      locaddr.sin6.sin6_flowinfo = 0;
888 		      remaddr.sin6.sin6_flowinfo = 0;
889 		      locaddr.sin6.sin6_scope_id = 0;
890 		      remaddr.sin6.sin6_scope_id = 0;
891 
892 		      addr_size = sizeof (struct sockaddr_in6);
893 		    }
894 
895 		  locaddr.sa.sa_family = remaddr.sa.sa_family = family;
896 
897 		  result = getnameinfo (&locaddr.sa, addr_size,
898 					local_address, sizeof (local_address),
899 					local_service, sizeof (local_service),
900 					NI_NUMERICHOST | NI_NUMERICSERV
901 					| (tcp ? 0 : NI_DGRAM));
902 		  if (result)
903 		    continue;
904 
905 		  result = getnameinfo (&remaddr.sa, addr_size,
906 					remote_address,
907 					sizeof (remote_address),
908 					remote_service,
909 					sizeof (remote_service),
910 					NI_NUMERICHOST | NI_NUMERICSERV
911 					| (tcp ? 0 : NI_DGRAM));
912 		  if (result)
913 		    continue;
914 
915 		  user_from_uid (user, sizeof (user), uid);
916 
917 		  string_xml_appendf
918 		    (buffer,
919 		     "<item>"
920 		     "<column name=\"local address\">%s</column>"
921 		     "<column name=\"local port\">%s</column>"
922 		     "<column name=\"remote address\">%s</column>"
923 		     "<column name=\"remote port\">%s</column>"
924 		     "<column name=\"state\">%s</column>"
925 		     "<column name=\"user\">%s</column>"
926 		     "<column name=\"family\">%s</column>"
927 		     "<column name=\"protocol\">%s</column>"
928 		     "</item>",
929 		     local_address,
930 		     local_service,
931 		     remote_address,
932 		     remote_service,
933 		     format_socket_state (state),
934 		     user,
935 		     (family == AF_INET) ? "INET" : "INET6",
936 		     tcp ? "STREAM" : "DGRAM");
937 		}
938 	    }
939 	}
940       while (!feof (fp.get ()));
941     }
942 }
943 
944 /* Collect data about internet sockets and write it into BUFFER.  */
945 
946 static std::string
947 linux_xfer_osdata_isockets ()
948 {
949   std::string buffer = "<osdata type=\"I sockets\">\n";
950 
951   print_sockets (AF_INET, 1, buffer);
952   print_sockets (AF_INET, 0, buffer);
953   print_sockets (AF_INET6, 1, buffer);
954   print_sockets (AF_INET6, 0, buffer);
955 
956   buffer += "</osdata>\n";
957 
958   return buffer;
959 }
960 
961 /* Converts the time SECONDS into textual form and copies it into a
962    buffer TIME, with at most MAXLEN characters copied.  */
963 
964 static void
965 time_from_time_t (char *time, int maxlen, TIME_T seconds)
966 {
967   if (!seconds)
968     time[0] = '\0';
969   else
970     {
971       time_t t = (time_t) seconds;
972 
973       /* Per the ctime_r manpage, this buffer needs to be at least 26
974 	 characters long.  */
975       char buf[30];
976       const char *time_str = ctime_r (&t, buf);
977       strncpy (time, time_str, maxlen - 1);
978       time[maxlen - 1] = '\0';
979     }
980 }
981 
982 /* Finds the group name for the group GID and copies it into GROUP.
983    At most MAXLEN characters are copied.  */
984 
985 static void
986 group_from_gid (char *group, int maxlen, gid_t gid)
987 {
988   struct group *grentry = getgrgid (gid);
989 
990   if (grentry)
991     {
992       strncpy (group, grentry->gr_name, maxlen - 1);
993       /* Ensure that the group name is null-terminated.  */
994       group[maxlen - 1] = '\0';
995     }
996   else
997     group[0] = '\0';
998 }
999 
1000 /* Collect data about shared memory recorded in /proc and write it
1001    into BUFFER.  */
1002 
1003 static std::string
1004 linux_xfer_osdata_shm ()
1005 {
1006   std::string buffer = "<osdata type=\"shared memory\">\n";
1007 
1008   gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
1009   if (fp)
1010     {
1011       char buf[8192];
1012 
1013       do
1014 	{
1015 	  if (fgets (buf, sizeof (buf), fp.get ()))
1016 	    {
1017 	      key_t key;
1018 	      uid_t uid, cuid;
1019 	      gid_t gid, cgid;
1020 	      PID_T cpid, lpid;
1021 	      int shmid, size, nattch;
1022 	      TIME_T atime, dtime, ctime;
1023 	      unsigned int perms;
1024 	      int items_read;
1025 
1026 	      items_read = sscanf (buf,
1027 				   "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
1028 				   &key, &shmid, &perms, &size,
1029 				   &cpid, &lpid,
1030 				   &nattch,
1031 				   &uid, &gid, &cuid, &cgid,
1032 				   &atime, &dtime, &ctime);
1033 
1034 	      if (items_read == 14)
1035 		{
1036 		  char user[UT_NAMESIZE], group[UT_NAMESIZE];
1037 		  char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1038 		  char ccmd[32], lcmd[32];
1039 		  char atime_str[32], dtime_str[32], ctime_str[32];
1040 
1041 		  user_from_uid (user, sizeof (user), uid);
1042 		  group_from_gid (group, sizeof (group), gid);
1043 		  user_from_uid (cuser, sizeof (cuser), cuid);
1044 		  group_from_gid (cgroup, sizeof (cgroup), cgid);
1045 
1046 		  command_from_pid (ccmd, sizeof (ccmd), cpid);
1047 		  command_from_pid (lcmd, sizeof (lcmd), lpid);
1048 
1049 		  time_from_time_t (atime_str, sizeof (atime_str), atime);
1050 		  time_from_time_t (dtime_str, sizeof (dtime_str), dtime);
1051 		  time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1052 
1053 		  string_xml_appendf
1054 		    (buffer,
1055 		     "<item>"
1056 		     "<column name=\"key\">%d</column>"
1057 		     "<column name=\"shmid\">%d</column>"
1058 		     "<column name=\"permissions\">%o</column>"
1059 		     "<column name=\"size\">%d</column>"
1060 		     "<column name=\"creator command\">%s</column>"
1061 		     "<column name=\"last op. command\">%s</column>"
1062 		     "<column name=\"num attached\">%d</column>"
1063 		     "<column name=\"user\">%s</column>"
1064 		     "<column name=\"group\">%s</column>"
1065 		     "<column name=\"creator user\">%s</column>"
1066 		     "<column name=\"creator group\">%s</column>"
1067 		     "<column name=\"last shmat() time\">%s</column>"
1068 		     "<column name=\"last shmdt() time\">%s</column>"
1069 		     "<column name=\"last shmctl() time\">%s</column>"
1070 		     "</item>",
1071 		     key,
1072 		     shmid,
1073 		     perms,
1074 		     size,
1075 		     ccmd,
1076 		     lcmd,
1077 		     nattch,
1078 		     user,
1079 		     group,
1080 		     cuser,
1081 		     cgroup,
1082 		     atime_str,
1083 		     dtime_str,
1084 		     ctime_str);
1085 		}
1086 	    }
1087 	}
1088       while (!feof (fp.get ()));
1089     }
1090 
1091   buffer += "</osdata>\n";
1092 
1093   return buffer;
1094 }
1095 
1096 /* Collect data about semaphores recorded in /proc and write it
1097    into BUFFER.  */
1098 
1099 static std::string
1100 linux_xfer_osdata_sem ()
1101 {
1102   std::string buffer = "<osdata type=\"semaphores\">\n";
1103 
1104   gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1105   if (fp)
1106     {
1107       char buf[8192];
1108 
1109       do
1110 	{
1111 	  if (fgets (buf, sizeof (buf), fp.get ()))
1112 	    {
1113 	      key_t key;
1114 	      uid_t uid, cuid;
1115 	      gid_t gid, cgid;
1116 	      unsigned int perms, nsems;
1117 	      int semid;
1118 	      TIME_T otime, ctime;
1119 	      int items_read;
1120 
1121 	      items_read = sscanf (buf,
1122 				   "%d %d %o %u %d %d %d %d %lld %lld",
1123 				   &key, &semid, &perms, &nsems,
1124 				   &uid, &gid, &cuid, &cgid,
1125 				   &otime, &ctime);
1126 
1127 	      if (items_read == 10)
1128 		{
1129 		  char user[UT_NAMESIZE], group[UT_NAMESIZE];
1130 		  char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1131 		  char otime_str[32], ctime_str[32];
1132 
1133 		  user_from_uid (user, sizeof (user), uid);
1134 		  group_from_gid (group, sizeof (group), gid);
1135 		  user_from_uid (cuser, sizeof (cuser), cuid);
1136 		  group_from_gid (cgroup, sizeof (cgroup), cgid);
1137 
1138 		  time_from_time_t (otime_str, sizeof (otime_str), otime);
1139 		  time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1140 
1141 		  string_xml_appendf
1142 		    (buffer,
1143 		     "<item>"
1144 		     "<column name=\"key\">%d</column>"
1145 		     "<column name=\"semid\">%d</column>"
1146 		     "<column name=\"permissions\">%o</column>"
1147 		     "<column name=\"num semaphores\">%u</column>"
1148 		     "<column name=\"user\">%s</column>"
1149 		     "<column name=\"group\">%s</column>"
1150 		     "<column name=\"creator user\">%s</column>"
1151 		     "<column name=\"creator group\">%s</column>"
1152 		     "<column name=\"last semop() time\">%s</column>"
1153 		     "<column name=\"last semctl() time\">%s</column>"
1154 		     "</item>",
1155 		     key,
1156 		     semid,
1157 		     perms,
1158 		     nsems,
1159 		     user,
1160 		     group,
1161 		     cuser,
1162 		     cgroup,
1163 		     otime_str,
1164 		     ctime_str);
1165 		}
1166 	    }
1167 	}
1168       while (!feof (fp.get ()));
1169     }
1170 
1171   buffer += "</osdata>\n";
1172 
1173   return buffer;
1174 }
1175 
1176 /* Collect data about message queues recorded in /proc and write it
1177    into BUFFER.  */
1178 
1179 static std::string
1180 linux_xfer_osdata_msg ()
1181 {
1182   std::string buffer = "<osdata type=\"message queues\">\n";
1183 
1184   gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1185   if (fp)
1186     {
1187       char buf[8192];
1188 
1189       do
1190 	{
1191 	  if (fgets (buf, sizeof (buf), fp.get ()))
1192 	    {
1193 	      key_t key;
1194 	      PID_T lspid, lrpid;
1195 	      uid_t uid, cuid;
1196 	      gid_t gid, cgid;
1197 	      unsigned int perms, cbytes, qnum;
1198 	      int msqid;
1199 	      TIME_T stime, rtime, ctime;
1200 	      int items_read;
1201 
1202 	      items_read = sscanf (buf,
1203 				   "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1204 				   &key, &msqid, &perms, &cbytes, &qnum,
1205 				   &lspid, &lrpid, &uid, &gid, &cuid, &cgid,
1206 				   &stime, &rtime, &ctime);
1207 
1208 	      if (items_read == 14)
1209 		{
1210 		  char user[UT_NAMESIZE], group[UT_NAMESIZE];
1211 		  char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1212 		  char lscmd[32], lrcmd[32];
1213 		  char stime_str[32], rtime_str[32], ctime_str[32];
1214 
1215 		  user_from_uid (user, sizeof (user), uid);
1216 		  group_from_gid (group, sizeof (group), gid);
1217 		  user_from_uid (cuser, sizeof (cuser), cuid);
1218 		  group_from_gid (cgroup, sizeof (cgroup), cgid);
1219 
1220 		  command_from_pid (lscmd, sizeof (lscmd), lspid);
1221 		  command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
1222 
1223 		  time_from_time_t (stime_str, sizeof (stime_str), stime);
1224 		  time_from_time_t (rtime_str, sizeof (rtime_str), rtime);
1225 		  time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1226 
1227 		  string_xml_appendf
1228 		    (buffer,
1229 		     "<item>"
1230 		     "<column name=\"key\">%d</column>"
1231 		     "<column name=\"msqid\">%d</column>"
1232 		     "<column name=\"permissions\">%o</column>"
1233 		     "<column name=\"num used bytes\">%u</column>"
1234 		     "<column name=\"num messages\">%u</column>"
1235 		     "<column name=\"last msgsnd() command\">%s</column>"
1236 		     "<column name=\"last msgrcv() command\">%s</column>"
1237 		     "<column name=\"user\">%s</column>"
1238 		     "<column name=\"group\">%s</column>"
1239 		     "<column name=\"creator user\">%s</column>"
1240 		     "<column name=\"creator group\">%s</column>"
1241 		     "<column name=\"last msgsnd() time\">%s</column>"
1242 		     "<column name=\"last msgrcv() time\">%s</column>"
1243 		     "<column name=\"last msgctl() time\">%s</column>"
1244 		     "</item>",
1245 		     key,
1246 		     msqid,
1247 		     perms,
1248 		     cbytes,
1249 		     qnum,
1250 		     lscmd,
1251 		     lrcmd,
1252 		     user,
1253 		     group,
1254 		     cuser,
1255 		     cgroup,
1256 		     stime_str,
1257 		     rtime_str,
1258 		     ctime_str);
1259 		}
1260 	    }
1261 	}
1262       while (!feof (fp.get ()));
1263     }
1264 
1265   buffer += "</osdata>\n";
1266 
1267   return buffer;
1268 }
1269 
1270 /* Collect data about loaded kernel modules and write it into
1271    BUFFER.  */
1272 
1273 static std::string
1274 linux_xfer_osdata_modules ()
1275 {
1276   std::string buffer = "<osdata type=\"modules\">\n";
1277 
1278   gdb_file_up fp = gdb_fopen_cloexec ("/proc/modules", "r");
1279   if (fp)
1280     {
1281       char buf[8192];
1282 
1283       do
1284 	{
1285 	  if (fgets (buf, sizeof (buf), fp.get ()))
1286 	    {
1287 	      char *name, *dependencies, *status, *tmp, *saveptr;
1288 	      unsigned int size;
1289 	      unsigned long long address;
1290 	      int uses;
1291 
1292 	      name = strtok_r (buf, " ", &saveptr);
1293 	      if (name == NULL)
1294 		continue;
1295 
1296 	      tmp = strtok_r (NULL, " ", &saveptr);
1297 	      if (tmp == NULL)
1298 		continue;
1299 	      if (sscanf (tmp, "%u", &size) != 1)
1300 		continue;
1301 
1302 	      tmp = strtok_r (NULL, " ", &saveptr);
1303 	      if (tmp == NULL)
1304 		continue;
1305 	      if (sscanf (tmp, "%d", &uses) != 1)
1306 		continue;
1307 
1308 	      dependencies = strtok_r (NULL, " ", &saveptr);
1309 	      if (dependencies == NULL)
1310 		continue;
1311 
1312 	      status = strtok_r (NULL, " ", &saveptr);
1313 	      if (status == NULL)
1314 		continue;
1315 
1316 	      tmp = strtok_r (NULL, "\n", &saveptr);
1317 	      if (tmp == NULL)
1318 		continue;
1319 	      if (sscanf (tmp, "%llx", &address) != 1)
1320 		continue;
1321 
1322 	      string_xml_appendf (buffer,
1323 				  "<item>"
1324 				  "<column name=\"name\">%s</column>"
1325 				  "<column name=\"size\">%u</column>"
1326 				  "<column name=\"num uses\">%d</column>"
1327 				  "<column name=\"dependencies\">%s</column>"
1328 				  "<column name=\"status\">%s</column>"
1329 				  "<column name=\"address\">%llx</column>"
1330 				  "</item>",
1331 				  name,
1332 				  size,
1333 				  uses,
1334 				  dependencies,
1335 				  status,
1336 				  address);
1337 	    }
1338 	}
1339       while (!feof (fp.get ()));
1340     }
1341 
1342   buffer += "</osdata>\n";
1343 
1344   return buffer;
1345 }
1346 
1347 static std::string linux_xfer_osdata_info_os_types ();
1348 
1349 static struct osdata_type {
1350   const char *type;
1351   const char *title;
1352   const char *description;
1353   std::string (*take_snapshot) ();
1354   std::string buffer;
1355 } osdata_table[] = {
1356   { "types", "Types", "Listing of info os types you can list",
1357     linux_xfer_osdata_info_os_types },
1358   { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1359     linux_xfer_osdata_cpus },
1360   { "files", "File descriptors", "Listing of all file descriptors",
1361     linux_xfer_osdata_fds },
1362   { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1363     linux_xfer_osdata_modules },
1364   { "msg", "Message queues", "Listing of all message queues",
1365     linux_xfer_osdata_msg },
1366   { "processes", "Processes", "Listing of all processes",
1367     linux_xfer_osdata_processes },
1368   { "procgroups", "Process groups", "Listing of all process groups",
1369     linux_xfer_osdata_processgroups },
1370   { "semaphores", "Semaphores", "Listing of all semaphores",
1371     linux_xfer_osdata_sem },
1372   { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1373     linux_xfer_osdata_shm },
1374   { "sockets", "Sockets", "Listing of all internet-domain sockets",
1375     linux_xfer_osdata_isockets },
1376   { "threads", "Threads", "Listing of all threads",
1377     linux_xfer_osdata_threads },
1378   { NULL, NULL, NULL }
1379 };
1380 
1381 /* Collect data about all types info os can show in BUFFER.  */
1382 
1383 static std::string
1384 linux_xfer_osdata_info_os_types ()
1385 {
1386   std::string buffer = "<osdata type=\"types\">\n";
1387 
1388   /* Start the below loop at 1, as we do not want to list ourselves.  */
1389   for (int i = 1; osdata_table[i].type; ++i)
1390     string_xml_appendf (buffer,
1391 			"<item>"
1392 			"<column name=\"Type\">%s</column>"
1393 			"<column name=\"Description\">%s</column>"
1394 			"<column name=\"Title\">%s</column>"
1395 			"</item>",
1396 			osdata_table[i].type,
1397 			osdata_table[i].description,
1398 			osdata_table[i].title);
1399 
1400   buffer += "</osdata>\n";
1401 
1402   return buffer;
1403 }
1404 
1405 
1406 /*  Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1407     If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT.  */
1408 
1409 static LONGEST
1410 common_getter (struct osdata_type *osd,
1411 	       gdb_byte *readbuf, ULONGEST offset, ULONGEST len)
1412 {
1413   gdb_assert (readbuf);
1414 
1415   if (offset == 0)
1416     osd->buffer = osd->take_snapshot ();
1417 
1418   if (offset >= osd->buffer.size ())
1419     {
1420       /* Done.  Get rid of the buffer.  */
1421       osd->buffer.clear ();
1422       return 0;
1423     }
1424 
1425   len = std::min (len, osd->buffer.size () - offset);
1426   memcpy (readbuf, &osd->buffer[offset], len);
1427 
1428   return len;
1429 
1430 }
1431 
1432 LONGEST
1433 linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
1434 			  ULONGEST offset, ULONGEST len)
1435 {
1436   if (!annex || *annex == '\0')
1437     {
1438       return common_getter (&osdata_table[0],
1439 			    readbuf, offset, len);
1440     }
1441   else
1442     {
1443       int i;
1444 
1445       for (i = 0; osdata_table[i].type; ++i)
1446 	{
1447 	  if (strcmp (annex, osdata_table[i].type) == 0)
1448 	    return common_getter (&osdata_table[i],
1449 				  readbuf, offset, len);
1450 	}
1451 
1452       return 0;
1453     }
1454 }
1455