1 /* Linux-specific functions to retrieve OS data.
3 Copyright (C) 2009-2022 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 #include "gdbsupport/common-defs.h"
21 #include "linux-osdata.h"
23 #include <sys/types.h>
24 #include <sys/sysinfo.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
35 #include "gdbsupport/xml-utils.h"
36 #include "gdbsupport/buffer.h"
39 #include "gdbsupport/filestuff.h"
42 #define NAMELEN(dirent) strlen ((dirent)->d_name)
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
48 typedef long long PID_T;
50 /* Define TIME_T to be at least as large as time_t, so that reading
51 time values embedded in /proc works consistently. */
53 typedef long long TIME_T;
55 #define MAX_PID_T_STRLEN (sizeof ("-9223372036854775808") - 1)
57 /* Returns the CPU core that thread PTID is currently running on. */
59 /* Compute and return the processor core of a given thread. */
62 linux_common_core_of_thread (ptid_t ptid)
64 char filename[sizeof ("/proc//task//stat") + 2 * MAX_PID_T_STRLEN];
67 sprintf (filename, "/proc/%lld/task/%lld/stat",
68 (PID_T) ptid.pid (), (PID_T) ptid.lwp ());
70 gdb::optional<std::string> content = read_text_file_to_string (filename);
71 if (!content.has_value ())
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)
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
82 for (int i = 0; i < 37; ++i)
85 pos = content->find_first_of (' ', pos);
86 if (pos == std::string::npos)
89 /* Find beginning of field. */
90 pos = content->find_first_not_of (' ', pos);
91 if (pos == std::string::npos)
95 if (sscanf (&(*content)[pos], "%d", &core) == 0)
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. */
106 command_from_pid (char *command, int maxlen, PID_T pid)
108 std::string stat_path = string_printf ("/proc/%lld/stat", pid);
109 gdb_file_up fp = gdb_fopen_cloexec (stat_path, "r");
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). */
120 int items_read = fscanf (fp.get (), "%lld %17s", &stat_pid, cmd);
122 if (items_read == 2 && pid == stat_pid)
124 cmd[strlen (cmd) - 1] = '\0'; /* Remove trailing parenthesis. */
125 strncpy (command, cmd + 1, maxlen); /* Ignore leading parenthesis. */
130 /* Return the PID if a /proc entry for the process cannot be found. */
131 snprintf (command, maxlen, "%lld", pid);
134 command[maxlen - 1] = '\0'; /* Ensure string is null-terminated. */
137 /* Returns the command-line of the process with the given PID. The
138 returned string needs to be freed using xfree after use. */
141 commandline_from_pid (PID_T pid)
143 std::string pathname = string_printf ("/proc/%lld/cmdline", pid);
144 char *commandline = NULL;
145 gdb_file_up f = gdb_fopen_cloexec (pathname, "r");
151 while (!feof (f.get ()))
154 size_t read_bytes = fread (buf, 1, sizeof (buf), f.get ());
158 commandline = (char *) xrealloc (commandline, len + read_bytes + 1);
159 memcpy (commandline + len, buf, read_bytes);
168 /* Replace null characters with spaces. */
169 for (i = 0; i < len; ++i)
170 if (commandline[i] == '\0')
171 commandline[i] = ' ';
173 commandline[len] = '\0';
177 /* Return the command in square brackets if the command-line
179 commandline = (char *) xmalloc (32);
180 commandline[0] = '[';
181 command_from_pid (commandline + 1, 31, pid);
183 len = strlen (commandline);
185 strcat (commandline, "]");
192 /* Finds the user name for the user UID and copies it into USER. At
193 most MAXLEN characters are copied. */
196 user_from_uid (char *user, int maxlen, uid_t uid)
198 struct passwd *pwentry;
201 getpwuid_r (uid, &pwd, buf, sizeof (buf), &pwentry);
205 strncpy (user, pwentry->pw_name, maxlen - 1);
206 /* Ensure that the user name is null-terminated. */
207 user[maxlen - 1] = '\0';
213 /* Finds the owner of process PID and returns the user id in OWNER.
214 Returns 0 if the owner was found, -1 otherwise. */
217 get_process_owner (uid_t *owner, PID_T pid)
220 char procentry[sizeof ("/proc/") + MAX_PID_T_STRLEN];
222 sprintf (procentry, "/proc/%lld", pid);
224 if (stat (procentry, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
226 *owner = statbuf.st_uid;
233 /* Find the CPU cores used by process PID and return them in CORES.
234 CORES points to an array of NUM_CORES elements. */
237 get_cores_used_by_process (PID_T pid, int *cores, const int num_cores)
239 char taskdir[sizeof ("/proc/") + MAX_PID_T_STRLEN + sizeof ("/task") - 1];
244 sprintf (taskdir, "/proc/%lld/task", pid);
245 dir = opendir (taskdir);
248 while ((dp = readdir (dir)) != NULL)
253 if (!isdigit (dp->d_name[0])
254 || NAMELEN (dp) > MAX_PID_T_STRLEN)
257 sscanf (dp->d_name, "%lld", &tid);
258 core = linux_common_core_of_thread (ptid_t ((pid_t) pid,
261 if (core >= 0 && core < num_cores)
274 /* get_core_array_size helper that uses /sys/devices/system/cpu/possible. */
276 static gdb::optional<size_t>
277 get_core_array_size_using_sys_possible ()
279 gdb::optional<std::string> possible
280 = read_text_file_to_string ("/sys/devices/system/cpu/possible");
282 if (!possible.has_value ())
285 /* The format is documented here:
287 https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst
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. */
294 unsigned long max_id = 0;
295 for (std::string::size_type start = 0; start < possible->size ();)
297 const char *start_p = &(*possible)[start];
300 /* Parse one number. */
302 unsigned long id = strtoul (start_p, &end_p, 10);
306 max_id = std::max (max_id, id);
308 start += end_p - start_p;
309 gdb_assert (start <= possible->size ());
311 /* Skip comma, dash, or new line (if we are at the end). */
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. */
323 get_core_array_size ()
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 ())
333 return sysconf (_SC_NPROCESSORS_ONLN);
337 linux_xfer_osdata_processes (struct buffer *buffer)
341 buffer_grow_str (buffer, "<osdata type=\"processes\">\n");
343 dirp = opendir ("/proc");
346 const int core_array_size = get_core_array_size ();
349 while ((dp = readdir (dirp)) != NULL)
353 char user[UT_NAMESIZE];
357 std::string cores_str;
360 if (!isdigit (dp->d_name[0])
361 || NAMELEN (dp) > MAX_PID_T_STRLEN)
364 sscanf (dp->d_name, "%lld", &pid);
365 command_line = commandline_from_pid (pid);
367 if (get_process_owner (&owner, pid) == 0)
368 user_from_uid (user, sizeof (user), owner);
372 /* Find CPU cores used by the process. */
373 cores = XCNEWVEC (int, core_array_size);
374 task_count = get_cores_used_by_process (pid, cores, core_array_size);
376 for (i = 0; i < core_array_size && task_count > 0; ++i)
379 string_appendf (cores_str, "%d", i);
381 task_count -= cores[i];
391 "<column name=\"pid\">%lld</column>"
392 "<column name=\"user\">%s</column>"
393 "<column name=\"command\">%s</column>"
394 "<column name=\"cores\">%s</column>"
398 command_line ? command_line : "",
401 xfree (command_line);
407 buffer_grow_str0 (buffer, "</osdata>\n");
410 /* A simple PID/PGID pair. */
412 struct pid_pgid_entry
414 pid_pgid_entry (PID_T pid_, PID_T pgid_)
415 : pid (pid_), pgid (pgid_)
418 /* Return true if this pid is the leader of its process group. */
420 bool is_leader () const
425 bool operator< (const pid_pgid_entry &other) const
428 if (this->pgid != other.pgid)
429 return this->pgid < other.pgid;
431 /* Process group leaders always come first... */
432 if (this->is_leader ())
434 if (!other.is_leader ())
437 else if (other.is_leader ())
440 /* ...else sort by PID. */
441 return this->pid < other.pid;
447 /* Collect all process groups from /proc in BUFFER. */
450 linux_xfer_osdata_processgroups (struct buffer *buffer)
454 buffer_grow_str (buffer, "<osdata type=\"process groups\">\n");
456 dirp = opendir ("/proc");
459 std::vector<pid_pgid_entry> process_list;
462 process_list.reserve (512);
464 /* Build list consisting of PIDs followed by their
466 while ((dp = readdir (dirp)) != NULL)
470 if (!isdigit (dp->d_name[0])
471 || NAMELEN (dp) > MAX_PID_T_STRLEN)
474 sscanf (dp->d_name, "%lld", &pid);
475 pgid = getpgid (pid);
478 process_list.emplace_back (pid, pgid);
483 /* Sort the process list. */
484 std::sort (process_list.begin (), process_list.end ());
486 for (const pid_pgid_entry &entry : process_list)
488 PID_T pid = entry.pid;
489 PID_T pgid = entry.pgid;
490 char leader_command[32];
493 command_from_pid (leader_command, sizeof (leader_command), pgid);
494 command_line = commandline_from_pid (pid);
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>"
507 command_line ? command_line : "");
509 xfree (command_line);
513 buffer_grow_str0 (buffer, "</osdata>\n");
516 /* Collect all the threads in /proc by iterating through processes and
517 then tasks within each process in BUFFER. */
520 linux_xfer_osdata_threads (struct buffer *buffer)
524 buffer_grow_str (buffer, "<osdata type=\"threads\">\n");
526 dirp = opendir ("/proc");
531 while ((dp = readdir (dirp)) != NULL)
534 char procentry[sizeof ("/proc/4294967295")];
536 if (!isdigit (dp->d_name[0])
537 || NAMELEN (dp) > sizeof ("4294967295") - 1)
540 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
542 if (stat (procentry, &statbuf) == 0
543 && S_ISDIR (statbuf.st_mode))
550 = string_printf ("/proc/%s/task", dp->d_name);
552 pid = atoi (dp->d_name);
553 command_from_pid (command, sizeof (command), pid);
555 dirp2 = opendir (pathname.c_str ());
561 while ((dp2 = readdir (dirp2)) != NULL)
566 if (!isdigit (dp2->d_name[0])
567 || NAMELEN (dp2) > sizeof ("4294967295") - 1)
570 tid = atoi (dp2->d_name);
571 core = linux_common_core_of_thread (ptid_t (pid, tid));
576 "<column name=\"pid\">%lld</column>"
577 "<column name=\"command\">%s</column>"
578 "<column name=\"tid\">%lld</column>"
579 "<column name=\"core\">%d</column>"
595 buffer_grow_str0 (buffer, "</osdata>\n");
598 /* Collect data about the cpus/cores on the system in BUFFER. */
601 linux_xfer_osdata_cpus (struct buffer *buffer)
605 buffer_grow_str (buffer, "<osdata type=\"cpus\">\n");
607 gdb_file_up fp = gdb_fopen_cloexec ("/proc/cpuinfo", "r");
614 if (fgets (buf, sizeof (buf), fp.get ()))
620 key = strtok_r (buf, ":", &saveptr);
624 value = strtok_r (NULL, ":", &saveptr);
628 while (key[i] != '\t' && key[i] != '\0')
634 while (value[i] != '\t' && value[i] != '\0')
639 if (strcmp (key, "processor") == 0)
642 buffer_grow_str (buffer, "<item>");
644 buffer_grow_str (buffer, "</item><item>");
649 buffer_xml_printf (buffer,
650 "<column name=\"%s\">%s</column>",
655 while (!feof (fp.get ()));
658 buffer_grow_str (buffer, "</item>");
661 buffer_grow_str0 (buffer, "</osdata>\n");
664 /* Collect all the open file descriptors found in /proc and put the details
665 found about them into BUFFER. */
668 linux_xfer_osdata_fds (struct buffer *buffer)
672 buffer_grow_str (buffer, "<osdata type=\"files\">\n");
674 dirp = opendir ("/proc");
679 while ((dp = readdir (dirp)) != NULL)
682 char procentry[sizeof ("/proc/4294967295")];
684 if (!isdigit (dp->d_name[0])
685 || NAMELEN (dp) > sizeof ("4294967295") - 1)
688 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
690 if (stat (procentry, &statbuf) == 0
691 && S_ISDIR (statbuf.st_mode))
697 pid = atoi (dp->d_name);
698 command_from_pid (command, sizeof (command), pid);
701 = string_printf ("/proc/%s/fd", dp->d_name);
702 dirp2 = opendir (pathname.c_str ());
708 while ((dp2 = readdir (dirp2)) != NULL)
713 if (!isdigit (dp2->d_name[0]))
717 = string_printf ("%s/%s", pathname.c_str (),
719 rslt = readlink (fdname.c_str (), buf,
727 "<column name=\"pid\">%s</column>"
728 "<column name=\"command\">%s</column>"
729 "<column name=\"file descriptor\">%s</column>"
730 "<column name=\"name\">%s</column>"
735 (rslt >= 0 ? buf : dp2->d_name));
746 buffer_grow_str0 (buffer, "</osdata>\n");
749 /* Returns the socket state STATE in textual form. */
752 format_socket_state (unsigned char state)
754 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
771 case TCP_ESTABLISHED:
772 return "ESTABLISHED";
801 struct sockaddr_in sin;
802 struct sockaddr_in6 sin6;
805 /* Auxiliary function used by linux_xfer_osdata_isocket. Formats
806 information for all open internet sockets of type FAMILY on the
807 system into BUFFER. If TCP is set, only TCP sockets are processed,
808 otherwise only UDP sockets are processed. */
811 print_sockets (unsigned short family, int tcp, struct buffer *buffer)
813 const char *proc_file;
815 if (family == AF_INET)
816 proc_file = tcp ? "/proc/net/tcp" : "/proc/net/udp";
817 else if (family == AF_INET6)
818 proc_file = tcp ? "/proc/net/tcp6" : "/proc/net/udp6";
822 gdb_file_up fp = gdb_fopen_cloexec (proc_file, "r");
829 if (fgets (buf, sizeof (buf), fp.get ()))
832 unsigned int local_port, remote_port, state;
833 char local_address[NI_MAXHOST], remote_address[NI_MAXHOST];
837 #error "local_address and remote_address buffers too small"
840 result = sscanf (buf,
841 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
842 local_address, &local_port,
843 remote_address, &remote_port,
849 union socket_addr locaddr, remaddr;
851 char user[UT_NAMESIZE];
852 char local_service[NI_MAXSERV], remote_service[NI_MAXSERV];
854 if (family == AF_INET)
856 sscanf (local_address, "%X",
857 &locaddr.sin.sin_addr.s_addr);
858 sscanf (remote_address, "%X",
859 &remaddr.sin.sin_addr.s_addr);
861 locaddr.sin.sin_port = htons (local_port);
862 remaddr.sin.sin_port = htons (remote_port);
864 addr_size = sizeof (struct sockaddr_in);
868 sscanf (local_address, "%8X%8X%8X%8X",
869 locaddr.sin6.sin6_addr.s6_addr32,
870 locaddr.sin6.sin6_addr.s6_addr32 + 1,
871 locaddr.sin6.sin6_addr.s6_addr32 + 2,
872 locaddr.sin6.sin6_addr.s6_addr32 + 3);
873 sscanf (remote_address, "%8X%8X%8X%8X",
874 remaddr.sin6.sin6_addr.s6_addr32,
875 remaddr.sin6.sin6_addr.s6_addr32 + 1,
876 remaddr.sin6.sin6_addr.s6_addr32 + 2,
877 remaddr.sin6.sin6_addr.s6_addr32 + 3);
879 locaddr.sin6.sin6_port = htons (local_port);
880 remaddr.sin6.sin6_port = htons (remote_port);
882 locaddr.sin6.sin6_flowinfo = 0;
883 remaddr.sin6.sin6_flowinfo = 0;
884 locaddr.sin6.sin6_scope_id = 0;
885 remaddr.sin6.sin6_scope_id = 0;
887 addr_size = sizeof (struct sockaddr_in6);
890 locaddr.sa.sa_family = remaddr.sa.sa_family = family;
892 result = getnameinfo (&locaddr.sa, addr_size,
893 local_address, sizeof (local_address),
894 local_service, sizeof (local_service),
895 NI_NUMERICHOST | NI_NUMERICSERV
896 | (tcp ? 0 : NI_DGRAM));
900 result = getnameinfo (&remaddr.sa, addr_size,
902 sizeof (remote_address),
904 sizeof (remote_service),
905 NI_NUMERICHOST | NI_NUMERICSERV
906 | (tcp ? 0 : NI_DGRAM));
910 user_from_uid (user, sizeof (user), uid);
915 "<column name=\"local address\">%s</column>"
916 "<column name=\"local port\">%s</column>"
917 "<column name=\"remote address\">%s</column>"
918 "<column name=\"remote port\">%s</column>"
919 "<column name=\"state\">%s</column>"
920 "<column name=\"user\">%s</column>"
921 "<column name=\"family\">%s</column>"
922 "<column name=\"protocol\">%s</column>"
928 format_socket_state (state),
930 (family == AF_INET) ? "INET" : "INET6",
931 tcp ? "STREAM" : "DGRAM");
935 while (!feof (fp.get ()));
939 /* Collect data about internet sockets and write it into BUFFER. */
942 linux_xfer_osdata_isockets (struct buffer *buffer)
944 buffer_grow_str (buffer, "<osdata type=\"I sockets\">\n");
946 print_sockets (AF_INET, 1, buffer);
947 print_sockets (AF_INET, 0, buffer);
948 print_sockets (AF_INET6, 1, buffer);
949 print_sockets (AF_INET6, 0, buffer);
951 buffer_grow_str0 (buffer, "</osdata>\n");
954 /* Converts the time SECONDS into textual form and copies it into a
955 buffer TIME, with at most MAXLEN characters copied. */
958 time_from_time_t (char *time, int maxlen, TIME_T seconds)
964 time_t t = (time_t) seconds;
966 /* Per the ctime_r manpage, this buffer needs to be at least 26
969 const char *time_str = ctime_r (&t, buf);
970 strncpy (time, time_str, maxlen - 1);
971 time[maxlen - 1] = '\0';
975 /* Finds the group name for the group GID and copies it into GROUP.
976 At most MAXLEN characters are copied. */
979 group_from_gid (char *group, int maxlen, gid_t gid)
981 struct group *grentry = getgrgid (gid);
985 strncpy (group, grentry->gr_name, maxlen - 1);
986 /* Ensure that the group name is null-terminated. */
987 group[maxlen - 1] = '\0';
993 /* Collect data about shared memory recorded in /proc and write it
997 linux_xfer_osdata_shm (struct buffer *buffer)
999 buffer_grow_str (buffer, "<osdata type=\"shared memory\">\n");
1001 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
1008 if (fgets (buf, sizeof (buf), fp.get ()))
1014 int shmid, size, nattch;
1015 TIME_T atime, dtime, ctime;
1019 items_read = sscanf (buf,
1020 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
1021 &key, &shmid, &perms, &size,
1024 &uid, &gid, &cuid, &cgid,
1025 &atime, &dtime, &ctime);
1027 if (items_read == 14)
1029 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1030 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1031 char ccmd[32], lcmd[32];
1032 char atime_str[32], dtime_str[32], ctime_str[32];
1034 user_from_uid (user, sizeof (user), uid);
1035 group_from_gid (group, sizeof (group), gid);
1036 user_from_uid (cuser, sizeof (cuser), cuid);
1037 group_from_gid (cgroup, sizeof (cgroup), cgid);
1039 command_from_pid (ccmd, sizeof (ccmd), cpid);
1040 command_from_pid (lcmd, sizeof (lcmd), lpid);
1042 time_from_time_t (atime_str, sizeof (atime_str), atime);
1043 time_from_time_t (dtime_str, sizeof (dtime_str), dtime);
1044 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1049 "<column name=\"key\">%d</column>"
1050 "<column name=\"shmid\">%d</column>"
1051 "<column name=\"permissions\">%o</column>"
1052 "<column name=\"size\">%d</column>"
1053 "<column name=\"creator command\">%s</column>"
1054 "<column name=\"last op. command\">%s</column>"
1055 "<column name=\"num attached\">%d</column>"
1056 "<column name=\"user\">%s</column>"
1057 "<column name=\"group\">%s</column>"
1058 "<column name=\"creator user\">%s</column>"
1059 "<column name=\"creator group\">%s</column>"
1060 "<column name=\"last shmat() time\">%s</column>"
1061 "<column name=\"last shmdt() time\">%s</column>"
1062 "<column name=\"last shmctl() time\">%s</column>"
1081 while (!feof (fp.get ()));
1084 buffer_grow_str0 (buffer, "</osdata>\n");
1087 /* Collect data about semaphores recorded in /proc and write it
1091 linux_xfer_osdata_sem (struct buffer *buffer)
1093 buffer_grow_str (buffer, "<osdata type=\"semaphores\">\n");
1095 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1102 if (fgets (buf, sizeof (buf), fp.get ()))
1107 unsigned int perms, nsems;
1109 TIME_T otime, ctime;
1112 items_read = sscanf (buf,
1113 "%d %d %o %u %d %d %d %d %lld %lld",
1114 &key, &semid, &perms, &nsems,
1115 &uid, &gid, &cuid, &cgid,
1118 if (items_read == 10)
1120 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1121 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1122 char otime_str[32], ctime_str[32];
1124 user_from_uid (user, sizeof (user), uid);
1125 group_from_gid (group, sizeof (group), gid);
1126 user_from_uid (cuser, sizeof (cuser), cuid);
1127 group_from_gid (cgroup, sizeof (cgroup), cgid);
1129 time_from_time_t (otime_str, sizeof (otime_str), otime);
1130 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1135 "<column name=\"key\">%d</column>"
1136 "<column name=\"semid\">%d</column>"
1137 "<column name=\"permissions\">%o</column>"
1138 "<column name=\"num semaphores\">%u</column>"
1139 "<column name=\"user\">%s</column>"
1140 "<column name=\"group\">%s</column>"
1141 "<column name=\"creator user\">%s</column>"
1142 "<column name=\"creator group\">%s</column>"
1143 "<column name=\"last semop() time\">%s</column>"
1144 "<column name=\"last semctl() time\">%s</column>"
1159 while (!feof (fp.get ()));
1162 buffer_grow_str0 (buffer, "</osdata>\n");
1165 /* Collect data about message queues recorded in /proc and write it
1169 linux_xfer_osdata_msg (struct buffer *buffer)
1171 buffer_grow_str (buffer, "<osdata type=\"message queues\">\n");
1173 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1180 if (fgets (buf, sizeof (buf), fp.get ()))
1186 unsigned int perms, cbytes, qnum;
1188 TIME_T stime, rtime, ctime;
1191 items_read = sscanf (buf,
1192 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1193 &key, &msqid, &perms, &cbytes, &qnum,
1194 &lspid, &lrpid, &uid, &gid, &cuid, &cgid,
1195 &stime, &rtime, &ctime);
1197 if (items_read == 14)
1199 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1200 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1201 char lscmd[32], lrcmd[32];
1202 char stime_str[32], rtime_str[32], ctime_str[32];
1204 user_from_uid (user, sizeof (user), uid);
1205 group_from_gid (group, sizeof (group), gid);
1206 user_from_uid (cuser, sizeof (cuser), cuid);
1207 group_from_gid (cgroup, sizeof (cgroup), cgid);
1209 command_from_pid (lscmd, sizeof (lscmd), lspid);
1210 command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
1212 time_from_time_t (stime_str, sizeof (stime_str), stime);
1213 time_from_time_t (rtime_str, sizeof (rtime_str), rtime);
1214 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1219 "<column name=\"key\">%d</column>"
1220 "<column name=\"msqid\">%d</column>"
1221 "<column name=\"permissions\">%o</column>"
1222 "<column name=\"num used bytes\">%u</column>"
1223 "<column name=\"num messages\">%u</column>"
1224 "<column name=\"last msgsnd() command\">%s</column>"
1225 "<column name=\"last msgrcv() command\">%s</column>"
1226 "<column name=\"user\">%s</column>"
1227 "<column name=\"group\">%s</column>"
1228 "<column name=\"creator user\">%s</column>"
1229 "<column name=\"creator group\">%s</column>"
1230 "<column name=\"last msgsnd() time\">%s</column>"
1231 "<column name=\"last msgrcv() time\">%s</column>"
1232 "<column name=\"last msgctl() time\">%s</column>"
1251 while (!feof (fp.get ()));
1254 buffer_grow_str0 (buffer, "</osdata>\n");
1257 /* Collect data about loaded kernel modules and write it into
1261 linux_xfer_osdata_modules (struct buffer *buffer)
1263 buffer_grow_str (buffer, "<osdata type=\"modules\">\n");
1265 gdb_file_up fp = gdb_fopen_cloexec ("/proc/modules", "r");
1272 if (fgets (buf, sizeof (buf), fp.get ()))
1274 char *name, *dependencies, *status, *tmp, *saveptr;
1276 unsigned long long address;
1279 name = strtok_r (buf, " ", &saveptr);
1283 tmp = strtok_r (NULL, " ", &saveptr);
1286 if (sscanf (tmp, "%u", &size) != 1)
1289 tmp = strtok_r (NULL, " ", &saveptr);
1292 if (sscanf (tmp, "%d", &uses) != 1)
1295 dependencies = strtok_r (NULL, " ", &saveptr);
1296 if (dependencies == NULL)
1299 status = strtok_r (NULL, " ", &saveptr);
1303 tmp = strtok_r (NULL, "\n", &saveptr);
1306 if (sscanf (tmp, "%llx", &address) != 1)
1309 buffer_xml_printf (buffer,
1311 "<column name=\"name\">%s</column>"
1312 "<column name=\"size\">%u</column>"
1313 "<column name=\"num uses\">%d</column>"
1314 "<column name=\"dependencies\">%s</column>"
1315 "<column name=\"status\">%s</column>"
1316 "<column name=\"address\">%llx</column>"
1326 while (!feof (fp.get ()));
1329 buffer_grow_str0 (buffer, "</osdata>\n");
1332 static void linux_xfer_osdata_info_os_types (struct buffer *buffer);
1334 static struct osdata_type {
1337 const char *description;
1338 void (*take_snapshot) (struct buffer *buffer);
1340 struct buffer buffer;
1341 } osdata_table[] = {
1342 { "types", "Types", "Listing of info os types you can list",
1343 linux_xfer_osdata_info_os_types, -1 },
1344 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1345 linux_xfer_osdata_cpus, -1 },
1346 { "files", "File descriptors", "Listing of all file descriptors",
1347 linux_xfer_osdata_fds, -1 },
1348 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1349 linux_xfer_osdata_modules, -1 },
1350 { "msg", "Message queues", "Listing of all message queues",
1351 linux_xfer_osdata_msg, -1 },
1352 { "processes", "Processes", "Listing of all processes",
1353 linux_xfer_osdata_processes, -1 },
1354 { "procgroups", "Process groups", "Listing of all process groups",
1355 linux_xfer_osdata_processgroups, -1 },
1356 { "semaphores", "Semaphores", "Listing of all semaphores",
1357 linux_xfer_osdata_sem, -1 },
1358 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1359 linux_xfer_osdata_shm, -1 },
1360 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1361 linux_xfer_osdata_isockets, -1 },
1362 { "threads", "Threads", "Listing of all threads",
1363 linux_xfer_osdata_threads, -1 },
1364 { NULL, NULL, NULL }
1367 /* Collect data about all types info os can show in BUFFER. */
1370 linux_xfer_osdata_info_os_types (struct buffer *buffer)
1372 buffer_grow_str (buffer, "<osdata type=\"types\">\n");
1374 /* Start the below loop at 1, as we do not want to list ourselves. */
1375 for (int i = 1; osdata_table[i].type; ++i)
1376 buffer_xml_printf (buffer,
1378 "<column name=\"Type\">%s</column>"
1379 "<column name=\"Description\">%s</column>"
1380 "<column name=\"Title\">%s</column>"
1382 osdata_table[i].type,
1383 osdata_table[i].description,
1384 osdata_table[i].title);
1386 buffer_grow_str0 (buffer, "</osdata>\n");
1390 /* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1391 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
1394 common_getter (struct osdata_type *osd,
1395 gdb_byte *readbuf, ULONGEST offset, ULONGEST len)
1397 gdb_assert (readbuf);
1401 if (osd->len_avail != -1 && osd->len_avail != 0)
1402 buffer_free (&osd->buffer);
1404 buffer_init (&osd->buffer);
1405 (osd->take_snapshot) (&osd->buffer);
1406 osd->len_avail = strlen (osd->buffer.buffer);
1408 if (offset >= osd->len_avail)
1410 /* Done. Get rid of the buffer. */
1411 buffer_free (&osd->buffer);
1415 if (len > osd->len_avail - offset)
1416 len = osd->len_avail - offset;
1417 memcpy (readbuf, osd->buffer.buffer + offset, len);
1424 linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
1425 ULONGEST offset, ULONGEST len)
1427 if (!annex || *annex == '\0')
1429 return common_getter (&osdata_table[0],
1430 readbuf, offset, len);
1436 for (i = 0; osdata_table[i].type; ++i)
1438 if (strcmp (annex, osdata_table[i].type) == 0)
1439 return common_getter (&osdata_table[i],
1440 readbuf, offset, len);