1 /* Linux-specific functions to retrieve OS data.
3 Copyright (C) 2009-2023 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 ()
340 std::string buffer = "<osdata type=\"processes\">\n";
342 dirp = opendir ("/proc");
345 const int core_array_size = get_core_array_size ();
348 while ((dp = readdir (dirp)) != NULL)
352 char user[UT_NAMESIZE];
356 std::string cores_str;
359 if (!isdigit (dp->d_name[0])
360 || NAMELEN (dp) > MAX_PID_T_STRLEN)
363 sscanf (dp->d_name, "%lld", &pid);
364 command_line = commandline_from_pid (pid);
366 if (get_process_owner (&owner, pid) == 0)
367 user_from_uid (user, sizeof (user), owner);
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);
375 for (i = 0; i < core_array_size && task_count > 0; ++i)
378 string_appendf (cores_str, "%d", i);
380 task_count -= cores[i];
390 "<column name=\"pid\">%lld</column>"
391 "<column name=\"user\">%s</column>"
392 "<column name=\"command\">%s</column>"
393 "<column name=\"cores\">%s</column>"
397 command_line ? command_line : "",
400 xfree (command_line);
406 buffer += "</osdata>\n";
411 /* A simple PID/PGID pair. */
413 struct pid_pgid_entry
415 pid_pgid_entry (PID_T pid_, PID_T pgid_)
416 : pid (pid_), pgid (pgid_)
419 /* Return true if this pid is the leader of its process group. */
421 bool is_leader () const
426 bool operator< (const pid_pgid_entry &other) const
429 if (this->pgid != other.pgid)
430 return this->pgid < other.pgid;
432 /* Process group leaders always come first... */
433 if (this->is_leader ())
435 if (!other.is_leader ())
438 else if (other.is_leader ())
441 /* ...else sort by PID. */
442 return this->pid < other.pid;
448 /* Collect all process groups from /proc in BUFFER. */
451 linux_xfer_osdata_processgroups ()
454 std::string 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 += "</osdata>\n";
518 /* Collect all the threads in /proc by iterating through processes and
519 then tasks within each process. */
522 linux_xfer_osdata_threads ()
525 std::string buffer = "<osdata type=\"threads\">\n";
527 dirp = opendir ("/proc");
532 while ((dp = readdir (dirp)) != NULL)
535 char procentry[sizeof ("/proc/4294967295")];
537 if (!isdigit (dp->d_name[0])
538 || NAMELEN (dp) > sizeof ("4294967295") - 1)
541 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
543 if (stat (procentry, &statbuf) == 0
544 && S_ISDIR (statbuf.st_mode))
551 = string_printf ("/proc/%s/task", dp->d_name);
553 pid = atoi (dp->d_name);
554 command_from_pid (command, sizeof (command), pid);
556 dirp2 = opendir (pathname.c_str ());
562 while ((dp2 = readdir (dirp2)) != NULL)
567 if (!isdigit (dp2->d_name[0])
568 || NAMELEN (dp2) > sizeof ("4294967295") - 1)
571 tid = atoi (dp2->d_name);
572 core = linux_common_core_of_thread (ptid_t (pid, tid));
577 "<column name=\"pid\">%lld</column>"
578 "<column name=\"command\">%s</column>"
579 "<column name=\"tid\">%lld</column>"
580 "<column name=\"core\">%d</column>"
596 buffer += "</osdata>\n";
601 /* Collect data about the cpus/cores on the system in BUFFER. */
604 linux_xfer_osdata_cpus ()
607 std::string buffer = "<osdata type=\"cpus\">\n";
609 gdb_file_up fp = gdb_fopen_cloexec ("/proc/cpuinfo", "r");
616 if (fgets (buf, sizeof (buf), fp.get ()))
622 key = strtok_r (buf, ":", &saveptr);
626 value = strtok_r (NULL, ":", &saveptr);
630 while (key[i] != '\t' && key[i] != '\0')
636 while (value[i] != '\t' && value[i] != '\0')
641 if (strcmp (key, "processor") == 0)
646 buffer += "</item><item>";
651 string_xml_appendf (buffer,
652 "<column name=\"%s\">%s</column>",
657 while (!feof (fp.get ()));
663 buffer += "</osdata>\n";
668 /* Collect all the open file descriptors found in /proc and put the details
669 found about them into BUFFER. */
672 linux_xfer_osdata_fds ()
675 std::string buffer = "<osdata type=\"files\">\n";
677 dirp = opendir ("/proc");
682 while ((dp = readdir (dirp)) != NULL)
685 char procentry[sizeof ("/proc/4294967295")];
687 if (!isdigit (dp->d_name[0])
688 || NAMELEN (dp) > sizeof ("4294967295") - 1)
691 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
693 if (stat (procentry, &statbuf) == 0
694 && S_ISDIR (statbuf.st_mode))
700 pid = atoi (dp->d_name);
701 command_from_pid (command, sizeof (command), pid);
704 = string_printf ("/proc/%s/fd", dp->d_name);
705 dirp2 = opendir (pathname.c_str ());
711 while ((dp2 = readdir (dirp2)) != NULL)
716 if (!isdigit (dp2->d_name[0]))
720 = string_printf ("%s/%s", pathname.c_str (),
722 rslt = readlink (fdname.c_str (), buf,
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>"
738 (rslt >= 0 ? buf : dp2->d_name));
749 buffer += "</osdata>\n";
754 /* Returns the socket state STATE in textual form. */
757 format_socket_state (unsigned char state)
759 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
776 case TCP_ESTABLISHED:
777 return "ESTABLISHED";
806 struct sockaddr_in sin;
807 struct sockaddr_in6 sin6;
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. */
816 print_sockets (unsigned short family, int tcp, std::string &buffer)
818 const char *proc_file;
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";
827 gdb_file_up fp = gdb_fopen_cloexec (proc_file, "r");
834 if (fgets (buf, sizeof (buf), fp.get ()))
837 unsigned int local_port, remote_port, state;
838 char local_address[NI_MAXHOST], remote_address[NI_MAXHOST];
842 #error "local_address and remote_address buffers too small"
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,
854 union socket_addr locaddr, remaddr;
856 char user[UT_NAMESIZE];
857 char local_service[NI_MAXSERV], remote_service[NI_MAXSERV];
859 if (family == AF_INET)
861 sscanf (local_address, "%X",
862 &locaddr.sin.sin_addr.s_addr);
863 sscanf (remote_address, "%X",
864 &remaddr.sin.sin_addr.s_addr);
866 locaddr.sin.sin_port = htons (local_port);
867 remaddr.sin.sin_port = htons (remote_port);
869 addr_size = sizeof (struct sockaddr_in);
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);
884 locaddr.sin6.sin6_port = htons (local_port);
885 remaddr.sin6.sin6_port = htons (remote_port);
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;
892 addr_size = sizeof (struct sockaddr_in6);
895 locaddr.sa.sa_family = remaddr.sa.sa_family = family;
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));
905 result = getnameinfo (&remaddr.sa, addr_size,
907 sizeof (remote_address),
909 sizeof (remote_service),
910 NI_NUMERICHOST | NI_NUMERICSERV
911 | (tcp ? 0 : NI_DGRAM));
915 user_from_uid (user, sizeof (user), uid);
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>"
933 format_socket_state (state),
935 (family == AF_INET) ? "INET" : "INET6",
936 tcp ? "STREAM" : "DGRAM");
940 while (!feof (fp.get ()));
944 /* Collect data about internet sockets and write it into BUFFER. */
947 linux_xfer_osdata_isockets ()
949 std::string buffer = "<osdata type=\"I sockets\">\n";
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);
956 buffer += "</osdata>\n";
961 /* Converts the time SECONDS into textual form and copies it into a
962 buffer TIME, with at most MAXLEN characters copied. */
965 time_from_time_t (char *time, int maxlen, TIME_T seconds)
971 time_t t = (time_t) seconds;
973 /* Per the ctime_r manpage, this buffer needs to be at least 26
976 const char *time_str = ctime_r (&t, buf);
977 strncpy (time, time_str, maxlen - 1);
978 time[maxlen - 1] = '\0';
982 /* Finds the group name for the group GID and copies it into GROUP.
983 At most MAXLEN characters are copied. */
986 group_from_gid (char *group, int maxlen, gid_t gid)
988 struct group *grentry = getgrgid (gid);
992 strncpy (group, grentry->gr_name, maxlen - 1);
993 /* Ensure that the group name is null-terminated. */
994 group[maxlen - 1] = '\0';
1000 /* Collect data about shared memory recorded in /proc and write it
1004 linux_xfer_osdata_shm ()
1006 std::string buffer = "<osdata type=\"shared memory\">\n";
1008 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
1015 if (fgets (buf, sizeof (buf), fp.get ()))
1021 int shmid, size, nattch;
1022 TIME_T atime, dtime, ctime;
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,
1031 &uid, &gid, &cuid, &cgid,
1032 &atime, &dtime, &ctime);
1034 if (items_read == 14)
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];
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);
1046 command_from_pid (ccmd, sizeof (ccmd), cpid);
1047 command_from_pid (lcmd, sizeof (lcmd), lpid);
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);
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>"
1088 while (!feof (fp.get ()));
1091 buffer += "</osdata>\n";
1096 /* Collect data about semaphores recorded in /proc and write it
1100 linux_xfer_osdata_sem ()
1102 std::string buffer = "<osdata type=\"semaphores\">\n";
1104 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1111 if (fgets (buf, sizeof (buf), fp.get ()))
1116 unsigned int perms, nsems;
1118 TIME_T otime, ctime;
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,
1127 if (items_read == 10)
1129 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1130 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1131 char otime_str[32], ctime_str[32];
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);
1138 time_from_time_t (otime_str, sizeof (otime_str), otime);
1139 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
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>"
1168 while (!feof (fp.get ()));
1171 buffer += "</osdata>\n";
1176 /* Collect data about message queues recorded in /proc and write it
1180 linux_xfer_osdata_msg ()
1182 std::string buffer = "<osdata type=\"message queues\">\n";
1184 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1191 if (fgets (buf, sizeof (buf), fp.get ()))
1197 unsigned int perms, cbytes, qnum;
1199 TIME_T stime, rtime, ctime;
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);
1208 if (items_read == 14)
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];
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);
1220 command_from_pid (lscmd, sizeof (lscmd), lspid);
1221 command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
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);
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>"
1262 while (!feof (fp.get ()));
1265 buffer += "</osdata>\n";
1270 /* Collect data about loaded kernel modules and write it into
1274 linux_xfer_osdata_modules ()
1276 std::string buffer = "<osdata type=\"modules\">\n";
1278 gdb_file_up fp = gdb_fopen_cloexec ("/proc/modules", "r");
1285 if (fgets (buf, sizeof (buf), fp.get ()))
1287 char *name, *dependencies, *status, *tmp, *saveptr;
1289 unsigned long long address;
1292 name = strtok_r (buf, " ", &saveptr);
1296 tmp = strtok_r (NULL, " ", &saveptr);
1299 if (sscanf (tmp, "%u", &size) != 1)
1302 tmp = strtok_r (NULL, " ", &saveptr);
1305 if (sscanf (tmp, "%d", &uses) != 1)
1308 dependencies = strtok_r (NULL, " ", &saveptr);
1309 if (dependencies == NULL)
1312 status = strtok_r (NULL, " ", &saveptr);
1316 tmp = strtok_r (NULL, "\n", &saveptr);
1319 if (sscanf (tmp, "%llx", &address) != 1)
1322 string_xml_appendf (buffer,
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>"
1339 while (!feof (fp.get ()));
1342 buffer += "</osdata>\n";
1347 static std::string linux_xfer_osdata_info_os_types ();
1349 static struct osdata_type {
1352 const char *description;
1353 std::string (*take_snapshot) ();
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 }
1381 /* Collect data about all types info os can show in BUFFER. */
1384 linux_xfer_osdata_info_os_types ()
1386 std::string buffer = "<osdata type=\"types\">\n";
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,
1392 "<column name=\"Type\">%s</column>"
1393 "<column name=\"Description\">%s</column>"
1394 "<column name=\"Title\">%s</column>"
1396 osdata_table[i].type,
1397 osdata_table[i].description,
1398 osdata_table[i].title);
1400 buffer += "</osdata>\n";
1406 /* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1407 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
1410 common_getter (struct osdata_type *osd,
1411 gdb_byte *readbuf, ULONGEST offset, ULONGEST len)
1413 gdb_assert (readbuf);
1416 osd->buffer = osd->take_snapshot ();
1418 if (offset >= osd->buffer.size ())
1420 /* Done. Get rid of the buffer. */
1421 osd->buffer.clear ();
1425 len = std::min (len, osd->buffer.size () - offset);
1426 memcpy (readbuf, &osd->buffer[offset], len);
1433 linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
1434 ULONGEST offset, ULONGEST len)
1436 if (!annex || *annex == '\0')
1438 return common_getter (&osdata_table[0],
1439 readbuf, offset, len);
1445 for (i = 0; osdata_table[i].type; ++i)
1447 if (strcmp (annex, osdata_table[i].type) == 0)
1448 return common_getter (&osdata_table[i],
1449 readbuf, offset, len);