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"
38 #include "gdbsupport/filestuff.h"
41 #define NAMELEN(dirent) strlen ((dirent)->d_name)
43 /* Define PID_T to be a fixed size that is at least as large as pid_t,
44 so that reading pid values embedded in /proc works
47 typedef long long PID_T
;
49 /* Define TIME_T to be at least as large as time_t, so that reading
50 time values embedded in /proc works consistently. */
52 typedef long long TIME_T
;
54 #define MAX_PID_T_STRLEN (sizeof ("-9223372036854775808") - 1)
56 /* Returns the CPU core that thread PTID is currently running on. */
58 /* Compute and return the processor core of a given thread. */
61 linux_common_core_of_thread (ptid_t ptid
)
63 char filename
[sizeof ("/proc//task//stat") + 2 * MAX_PID_T_STRLEN
];
66 sprintf (filename
, "/proc/%lld/task/%lld/stat",
67 (PID_T
) ptid
.pid (), (PID_T
) ptid
.lwp ());
69 gdb::optional
<std::string
> content
= read_text_file_to_string (filename
);
70 if (!content
.has_value ())
73 /* ps command also relies on no trailing fields ever contain ')'. */
74 std::string::size_type pos
= content
->find_last_of (')');
75 if (pos
== std::string::npos
)
78 /* If the first field after program name has index 0, then core number is
79 the field with index 36 (so, the 37th). There's no constant for that
81 for (int i
= 0; i
< 37; ++i
)
84 pos
= content
->find_first_of (' ', pos
);
85 if (pos
== std::string::npos
)
88 /* Find beginning of field. */
89 pos
= content
->find_first_not_of (' ', pos
);
90 if (pos
== std::string::npos
)
94 if (sscanf (&(*content
)[pos
], "%d", &core
) == 0)
100 /* Finds the command-line of process PID and copies it into COMMAND.
101 At most MAXLEN characters are copied. If the command-line cannot
102 be found, PID is copied into command in text-form. */
105 command_from_pid (char *command
, int maxlen
, PID_T pid
)
107 std::string stat_path
= string_printf ("/proc/%lld/stat", pid
);
108 gdb_file_up fp
= gdb_fopen_cloexec (stat_path
, "r");
114 /* sizeof (cmd) should be greater or equal to TASK_COMM_LEN (in
115 include/linux/sched.h in the Linux kernel sources) plus two
116 (for the brackets). */
119 int items_read
= fscanf (fp
.get (), "%lld %17s", &stat_pid
, cmd
);
121 if (items_read
== 2 && pid
== stat_pid
)
123 cmd
[strlen (cmd
) - 1] = '\0'; /* Remove trailing parenthesis. */
124 strncpy (command
, cmd
+ 1, maxlen
); /* Ignore leading parenthesis. */
129 /* Return the PID if a /proc entry for the process cannot be found. */
130 snprintf (command
, maxlen
, "%lld", pid
);
133 command
[maxlen
- 1] = '\0'; /* Ensure string is null-terminated. */
136 /* Returns the command-line of the process with the given PID. */
139 commandline_from_pid (PID_T pid
)
141 std::string pathname
= string_printf ("/proc/%lld/cmdline", pid
);
142 std::string commandline
;
143 gdb_file_up f
= gdb_fopen_cloexec (pathname
, "r");
147 while (!feof (f
.get ()))
150 size_t read_bytes
= fread (buf
, 1, sizeof (buf
), f
.get ());
153 commandline
.append (buf
, read_bytes
);
156 if (!commandline
.empty ())
158 /* Replace null characters with spaces. */
159 for (char &c
: commandline
)
165 /* Return the command in square brackets if the command-line
168 command_from_pid (cmd
, 31, pid
);
169 commandline
= std::string ("[") + cmd
+ "]";
176 /* Finds the user name for the user UID and copies it into USER. At
177 most MAXLEN characters are copied. */
180 user_from_uid (char *user
, int maxlen
, uid_t uid
)
182 struct passwd
*pwentry
;
185 getpwuid_r (uid
, &pwd
, buf
, sizeof (buf
), &pwentry
);
189 strncpy (user
, pwentry
->pw_name
, maxlen
- 1);
190 /* Ensure that the user name is null-terminated. */
191 user
[maxlen
- 1] = '\0';
197 /* Finds the owner of process PID and returns the user id in OWNER.
198 Returns 0 if the owner was found, -1 otherwise. */
201 get_process_owner (uid_t
*owner
, PID_T pid
)
204 char procentry
[sizeof ("/proc/") + MAX_PID_T_STRLEN
];
206 sprintf (procentry
, "/proc/%lld", pid
);
208 if (stat (procentry
, &statbuf
) == 0 && S_ISDIR (statbuf
.st_mode
))
210 *owner
= statbuf
.st_uid
;
217 /* Find the CPU cores used by process PID and return them in CORES.
218 CORES points to an array of NUM_CORES elements. */
221 get_cores_used_by_process (PID_T pid
, int *cores
, const int num_cores
)
223 char taskdir
[sizeof ("/proc/") + MAX_PID_T_STRLEN
+ sizeof ("/task") - 1];
228 sprintf (taskdir
, "/proc/%lld/task", pid
);
229 dir
= opendir (taskdir
);
232 while ((dp
= readdir (dir
)) != NULL
)
237 if (!isdigit (dp
->d_name
[0])
238 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
241 sscanf (dp
->d_name
, "%lld", &tid
);
242 core
= linux_common_core_of_thread (ptid_t ((pid_t
) pid
,
245 if (core
>= 0 && core
< num_cores
)
258 /* get_core_array_size helper that uses /sys/devices/system/cpu/possible. */
260 static gdb::optional
<size_t>
261 get_core_array_size_using_sys_possible ()
263 gdb::optional
<std::string
> possible
264 = read_text_file_to_string ("/sys/devices/system/cpu/possible");
266 if (!possible
.has_value ())
269 /* The format is documented here:
271 https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst
273 For the purpose of this function, we assume the file can contain a complex
274 set of ranges, like `2,4-31,32-63`. Read all number, disregarding commands
275 and dashes, in order to find the largest possible core number. The size
276 of the array to allocate is that plus one. */
278 unsigned long max_id
= 0;
279 for (std::string::size_type start
= 0; start
< possible
->size ();)
281 const char *start_p
= &(*possible
)[start
];
284 /* Parse one number. */
286 unsigned long id
= strtoul (start_p
, &end_p
, 10);
290 max_id
= std::max (max_id
, id
);
292 start
+= end_p
- start_p
;
293 gdb_assert (start
<= possible
->size ());
295 /* Skip comma, dash, or new line (if we are at the end). */
302 /* Return the array size to allocate in order to be able to index it using
303 CPU core numbers. This may be more than the actual number of cores if
304 the core numbers are not contiguous. */
307 get_core_array_size ()
309 /* Using /sys/.../possible is preferred, because it handles the case where
310 we are in a container that has access to a subset of the host's cores.
311 It will return a size that considers all the CPU cores available to the
312 host. If that fails for some reason, fall back to sysconf. */
313 gdb::optional
<size_t> count
= get_core_array_size_using_sys_possible ();
314 if (count
.has_value ())
317 return sysconf (_SC_NPROCESSORS_ONLN
);
321 linux_xfer_osdata_processes ()
324 std::string buffer
= "<osdata type=\"processes\">\n";
326 dirp
= opendir ("/proc");
329 const int core_array_size
= get_core_array_size ();
332 while ((dp
= readdir (dirp
)) != NULL
)
336 char user
[UT_NAMESIZE
];
339 std::string cores_str
;
342 if (!isdigit (dp
->d_name
[0])
343 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
346 sscanf (dp
->d_name
, "%lld", &pid
);
347 std::string command_line
= commandline_from_pid (pid
);
349 if (get_process_owner (&owner
, pid
) == 0)
350 user_from_uid (user
, sizeof (user
), owner
);
354 /* Find CPU cores used by the process. */
355 cores
= XCNEWVEC (int, core_array_size
);
356 task_count
= get_cores_used_by_process (pid
, cores
, core_array_size
);
358 for (i
= 0; i
< core_array_size
&& task_count
> 0; ++i
)
361 string_appendf (cores_str
, "%d", i
);
363 task_count
-= cores
[i
];
373 "<column name=\"pid\">%lld</column>"
374 "<column name=\"user\">%s</column>"
375 "<column name=\"command\">%s</column>"
376 "<column name=\"cores\">%s</column>"
380 command_line
.c_str (),
387 buffer
+= "</osdata>\n";
392 /* A simple PID/PGID pair. */
394 struct pid_pgid_entry
396 pid_pgid_entry (PID_T pid_
, PID_T pgid_
)
397 : pid (pid_
), pgid (pgid_
)
400 /* Return true if this pid is the leader of its process group. */
402 bool is_leader () const
407 bool operator< (const pid_pgid_entry
&other
) const
410 if (this->pgid
!= other
.pgid
)
411 return this->pgid
< other
.pgid
;
413 /* Process group leaders always come first... */
414 if (this->is_leader ())
416 if (!other
.is_leader ())
419 else if (other
.is_leader ())
422 /* ...else sort by PID. */
423 return this->pid
< other
.pid
;
429 /* Collect all process groups from /proc in BUFFER. */
432 linux_xfer_osdata_processgroups ()
435 std::string buffer
= "<osdata type=\"process groups\">\n";
437 dirp
= opendir ("/proc");
440 std::vector
<pid_pgid_entry
> process_list
;
443 process_list
.reserve (512);
445 /* Build list consisting of PIDs followed by their
447 while ((dp
= readdir (dirp
)) != NULL
)
451 if (!isdigit (dp
->d_name
[0])
452 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
455 sscanf (dp
->d_name
, "%lld", &pid
);
456 pgid
= getpgid (pid
);
459 process_list
.emplace_back (pid
, pgid
);
464 /* Sort the process list. */
465 std::sort (process_list
.begin (), process_list
.end ());
467 for (const pid_pgid_entry
&entry
: process_list
)
469 PID_T pid
= entry
.pid
;
470 PID_T pgid
= entry
.pgid
;
471 char leader_command
[32];
473 command_from_pid (leader_command
, sizeof (leader_command
), pgid
);
474 std::string command_line
= commandline_from_pid (pid
);
479 "<column name=\"pgid\">%lld</column>"
480 "<column name=\"leader command\">%s</column>"
481 "<column name=\"pid\">%lld</column>"
482 "<column name=\"command line\">%s</column>"
487 command_line
.c_str ());
491 buffer
+= "</osdata>\n";
496 /* Collect all the threads in /proc by iterating through processes and
497 then tasks within each process. */
500 linux_xfer_osdata_threads ()
503 std::string buffer
= "<osdata type=\"threads\">\n";
505 dirp
= opendir ("/proc");
510 while ((dp
= readdir (dirp
)) != NULL
)
513 char procentry
[sizeof ("/proc/4294967295")];
515 if (!isdigit (dp
->d_name
[0])
516 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
519 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
521 if (stat (procentry
, &statbuf
) == 0
522 && S_ISDIR (statbuf
.st_mode
))
529 = string_printf ("/proc/%s/task", dp
->d_name
);
531 pid
= atoi (dp
->d_name
);
532 command_from_pid (command
, sizeof (command
), pid
);
534 dirp2
= opendir (pathname
.c_str ());
540 while ((dp2
= readdir (dirp2
)) != NULL
)
545 if (!isdigit (dp2
->d_name
[0])
546 || NAMELEN (dp2
) > sizeof ("4294967295") - 1)
549 tid
= atoi (dp2
->d_name
);
550 core
= linux_common_core_of_thread (ptid_t (pid
, tid
));
555 "<column name=\"pid\">%lld</column>"
556 "<column name=\"command\">%s</column>"
557 "<column name=\"tid\">%lld</column>"
558 "<column name=\"core\">%d</column>"
574 buffer
+= "</osdata>\n";
579 /* Collect data about the cpus/cores on the system in BUFFER. */
582 linux_xfer_osdata_cpus ()
585 std::string buffer
= "<osdata type=\"cpus\">\n";
587 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/cpuinfo", "r");
594 if (fgets (buf
, sizeof (buf
), fp
.get ()))
600 key
= strtok_r (buf
, ":", &saveptr
);
604 value
= strtok_r (NULL
, ":", &saveptr
);
608 while (key
[i
] != '\t' && key
[i
] != '\0')
614 while (value
[i
] != '\t' && value
[i
] != '\0')
619 if (strcmp (key
, "processor") == 0)
624 buffer
+= "</item><item>";
629 string_xml_appendf (buffer
,
630 "<column name=\"%s\">%s</column>",
635 while (!feof (fp
.get ()));
641 buffer
+= "</osdata>\n";
646 /* Collect all the open file descriptors found in /proc and put the details
647 found about them into BUFFER. */
650 linux_xfer_osdata_fds ()
653 std::string buffer
= "<osdata type=\"files\">\n";
655 dirp
= opendir ("/proc");
660 while ((dp
= readdir (dirp
)) != NULL
)
663 char procentry
[sizeof ("/proc/4294967295")];
665 if (!isdigit (dp
->d_name
[0])
666 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
669 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
671 if (stat (procentry
, &statbuf
) == 0
672 && S_ISDIR (statbuf
.st_mode
))
678 pid
= atoi (dp
->d_name
);
679 command_from_pid (command
, sizeof (command
), pid
);
682 = string_printf ("/proc/%s/fd", dp
->d_name
);
683 dirp2
= opendir (pathname
.c_str ());
689 while ((dp2
= readdir (dirp2
)) != NULL
)
694 if (!isdigit (dp2
->d_name
[0]))
698 = string_printf ("%s/%s", pathname
.c_str (),
700 rslt
= readlink (fdname
.c_str (), buf
,
708 "<column name=\"pid\">%s</column>"
709 "<column name=\"command\">%s</column>"
710 "<column name=\"file descriptor\">%s</column>"
711 "<column name=\"name\">%s</column>"
716 (rslt
>= 0 ? buf
: dp2
->d_name
));
727 buffer
+= "</osdata>\n";
732 /* Returns the socket state STATE in textual form. */
735 format_socket_state (unsigned char state
)
737 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
754 case TCP_ESTABLISHED
:
755 return "ESTABLISHED";
784 struct sockaddr_in sin
;
785 struct sockaddr_in6 sin6
;
788 /* Auxiliary function used by linux_xfer_osdata_isocket. Formats
789 information for all open internet sockets of type FAMILY on the
790 system into BUFFER. If TCP is set, only TCP sockets are processed,
791 otherwise only UDP sockets are processed. */
794 print_sockets (unsigned short family
, int tcp
, std::string
&buffer
)
796 const char *proc_file
;
798 if (family
== AF_INET
)
799 proc_file
= tcp
? "/proc/net/tcp" : "/proc/net/udp";
800 else if (family
== AF_INET6
)
801 proc_file
= tcp
? "/proc/net/tcp6" : "/proc/net/udp6";
805 gdb_file_up fp
= gdb_fopen_cloexec (proc_file
, "r");
812 if (fgets (buf
, sizeof (buf
), fp
.get ()))
815 unsigned int local_port
, remote_port
, state
;
816 char local_address
[NI_MAXHOST
], remote_address
[NI_MAXHOST
];
820 #error "local_address and remote_address buffers too small"
823 result
= sscanf (buf
,
824 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
825 local_address
, &local_port
,
826 remote_address
, &remote_port
,
832 union socket_addr locaddr
, remaddr
;
834 char user
[UT_NAMESIZE
];
835 char local_service
[NI_MAXSERV
], remote_service
[NI_MAXSERV
];
837 if (family
== AF_INET
)
839 sscanf (local_address
, "%X",
840 &locaddr
.sin
.sin_addr
.s_addr
);
841 sscanf (remote_address
, "%X",
842 &remaddr
.sin
.sin_addr
.s_addr
);
844 locaddr
.sin
.sin_port
= htons (local_port
);
845 remaddr
.sin
.sin_port
= htons (remote_port
);
847 addr_size
= sizeof (struct sockaddr_in
);
851 sscanf (local_address
, "%8X%8X%8X%8X",
852 locaddr
.sin6
.sin6_addr
.s6_addr32
,
853 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
854 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
855 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
856 sscanf (remote_address
, "%8X%8X%8X%8X",
857 remaddr
.sin6
.sin6_addr
.s6_addr32
,
858 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
859 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
860 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
862 locaddr
.sin6
.sin6_port
= htons (local_port
);
863 remaddr
.sin6
.sin6_port
= htons (remote_port
);
865 locaddr
.sin6
.sin6_flowinfo
= 0;
866 remaddr
.sin6
.sin6_flowinfo
= 0;
867 locaddr
.sin6
.sin6_scope_id
= 0;
868 remaddr
.sin6
.sin6_scope_id
= 0;
870 addr_size
= sizeof (struct sockaddr_in6
);
873 locaddr
.sa
.sa_family
= remaddr
.sa
.sa_family
= family
;
875 result
= getnameinfo (&locaddr
.sa
, addr_size
,
876 local_address
, sizeof (local_address
),
877 local_service
, sizeof (local_service
),
878 NI_NUMERICHOST
| NI_NUMERICSERV
879 | (tcp
? 0 : NI_DGRAM
));
883 result
= getnameinfo (&remaddr
.sa
, addr_size
,
885 sizeof (remote_address
),
887 sizeof (remote_service
),
888 NI_NUMERICHOST
| NI_NUMERICSERV
889 | (tcp
? 0 : NI_DGRAM
));
893 user_from_uid (user
, sizeof (user
), uid
);
898 "<column name=\"local address\">%s</column>"
899 "<column name=\"local port\">%s</column>"
900 "<column name=\"remote address\">%s</column>"
901 "<column name=\"remote port\">%s</column>"
902 "<column name=\"state\">%s</column>"
903 "<column name=\"user\">%s</column>"
904 "<column name=\"family\">%s</column>"
905 "<column name=\"protocol\">%s</column>"
911 format_socket_state (state
),
913 (family
== AF_INET
) ? "INET" : "INET6",
914 tcp
? "STREAM" : "DGRAM");
918 while (!feof (fp
.get ()));
922 /* Collect data about internet sockets and write it into BUFFER. */
925 linux_xfer_osdata_isockets ()
927 std::string buffer
= "<osdata type=\"I sockets\">\n";
929 print_sockets (AF_INET
, 1, buffer
);
930 print_sockets (AF_INET
, 0, buffer
);
931 print_sockets (AF_INET6
, 1, buffer
);
932 print_sockets (AF_INET6
, 0, buffer
);
934 buffer
+= "</osdata>\n";
939 /* Converts the time SECONDS into textual form and copies it into a
940 buffer TIME, with at most MAXLEN characters copied. */
943 time_from_time_t (char *time
, int maxlen
, TIME_T seconds
)
949 time_t t
= (time_t) seconds
;
951 /* Per the ctime_r manpage, this buffer needs to be at least 26
954 const char *time_str
= ctime_r (&t
, buf
);
955 strncpy (time
, time_str
, maxlen
- 1);
956 time
[maxlen
- 1] = '\0';
960 /* Finds the group name for the group GID and copies it into GROUP.
961 At most MAXLEN characters are copied. */
964 group_from_gid (char *group
, int maxlen
, gid_t gid
)
966 struct group
*grentry
= getgrgid (gid
);
970 strncpy (group
, grentry
->gr_name
, maxlen
- 1);
971 /* Ensure that the group name is null-terminated. */
972 group
[maxlen
- 1] = '\0';
978 /* Collect data about shared memory recorded in /proc and write it
982 linux_xfer_osdata_shm ()
984 std::string buffer
= "<osdata type=\"shared memory\">\n";
986 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
993 if (fgets (buf
, sizeof (buf
), fp
.get ()))
999 int shmid
, size
, nattch
;
1000 TIME_T atime
, dtime
, ctime
;
1004 items_read
= sscanf (buf
,
1005 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
1006 &key
, &shmid
, &perms
, &size
,
1009 &uid
, &gid
, &cuid
, &cgid
,
1010 &atime
, &dtime
, &ctime
);
1012 if (items_read
== 14)
1014 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1015 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1016 char ccmd
[32], lcmd
[32];
1017 char atime_str
[32], dtime_str
[32], ctime_str
[32];
1019 user_from_uid (user
, sizeof (user
), uid
);
1020 group_from_gid (group
, sizeof (group
), gid
);
1021 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1022 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1024 command_from_pid (ccmd
, sizeof (ccmd
), cpid
);
1025 command_from_pid (lcmd
, sizeof (lcmd
), lpid
);
1027 time_from_time_t (atime_str
, sizeof (atime_str
), atime
);
1028 time_from_time_t (dtime_str
, sizeof (dtime_str
), dtime
);
1029 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1034 "<column name=\"key\">%d</column>"
1035 "<column name=\"shmid\">%d</column>"
1036 "<column name=\"permissions\">%o</column>"
1037 "<column name=\"size\">%d</column>"
1038 "<column name=\"creator command\">%s</column>"
1039 "<column name=\"last op. command\">%s</column>"
1040 "<column name=\"num attached\">%d</column>"
1041 "<column name=\"user\">%s</column>"
1042 "<column name=\"group\">%s</column>"
1043 "<column name=\"creator user\">%s</column>"
1044 "<column name=\"creator group\">%s</column>"
1045 "<column name=\"last shmat() time\">%s</column>"
1046 "<column name=\"last shmdt() time\">%s</column>"
1047 "<column name=\"last shmctl() time\">%s</column>"
1066 while (!feof (fp
.get ()));
1069 buffer
+= "</osdata>\n";
1074 /* Collect data about semaphores recorded in /proc and write it
1078 linux_xfer_osdata_sem ()
1080 std::string buffer
= "<osdata type=\"semaphores\">\n";
1082 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1089 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1094 unsigned int perms
, nsems
;
1096 TIME_T otime
, ctime
;
1099 items_read
= sscanf (buf
,
1100 "%d %d %o %u %d %d %d %d %lld %lld",
1101 &key
, &semid
, &perms
, &nsems
,
1102 &uid
, &gid
, &cuid
, &cgid
,
1105 if (items_read
== 10)
1107 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1108 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1109 char otime_str
[32], ctime_str
[32];
1111 user_from_uid (user
, sizeof (user
), uid
);
1112 group_from_gid (group
, sizeof (group
), gid
);
1113 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1114 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1116 time_from_time_t (otime_str
, sizeof (otime_str
), otime
);
1117 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1122 "<column name=\"key\">%d</column>"
1123 "<column name=\"semid\">%d</column>"
1124 "<column name=\"permissions\">%o</column>"
1125 "<column name=\"num semaphores\">%u</column>"
1126 "<column name=\"user\">%s</column>"
1127 "<column name=\"group\">%s</column>"
1128 "<column name=\"creator user\">%s</column>"
1129 "<column name=\"creator group\">%s</column>"
1130 "<column name=\"last semop() time\">%s</column>"
1131 "<column name=\"last semctl() time\">%s</column>"
1146 while (!feof (fp
.get ()));
1149 buffer
+= "</osdata>\n";
1154 /* Collect data about message queues recorded in /proc and write it
1158 linux_xfer_osdata_msg ()
1160 std::string buffer
= "<osdata type=\"message queues\">\n";
1162 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1169 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1175 unsigned int perms
, cbytes
, qnum
;
1177 TIME_T stime
, rtime
, ctime
;
1180 items_read
= sscanf (buf
,
1181 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1182 &key
, &msqid
, &perms
, &cbytes
, &qnum
,
1183 &lspid
, &lrpid
, &uid
, &gid
, &cuid
, &cgid
,
1184 &stime
, &rtime
, &ctime
);
1186 if (items_read
== 14)
1188 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1189 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1190 char lscmd
[32], lrcmd
[32];
1191 char stime_str
[32], rtime_str
[32], ctime_str
[32];
1193 user_from_uid (user
, sizeof (user
), uid
);
1194 group_from_gid (group
, sizeof (group
), gid
);
1195 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1196 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1198 command_from_pid (lscmd
, sizeof (lscmd
), lspid
);
1199 command_from_pid (lrcmd
, sizeof (lrcmd
), lrpid
);
1201 time_from_time_t (stime_str
, sizeof (stime_str
), stime
);
1202 time_from_time_t (rtime_str
, sizeof (rtime_str
), rtime
);
1203 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1208 "<column name=\"key\">%d</column>"
1209 "<column name=\"msqid\">%d</column>"
1210 "<column name=\"permissions\">%o</column>"
1211 "<column name=\"num used bytes\">%u</column>"
1212 "<column name=\"num messages\">%u</column>"
1213 "<column name=\"last msgsnd() command\">%s</column>"
1214 "<column name=\"last msgrcv() command\">%s</column>"
1215 "<column name=\"user\">%s</column>"
1216 "<column name=\"group\">%s</column>"
1217 "<column name=\"creator user\">%s</column>"
1218 "<column name=\"creator group\">%s</column>"
1219 "<column name=\"last msgsnd() time\">%s</column>"
1220 "<column name=\"last msgrcv() time\">%s</column>"
1221 "<column name=\"last msgctl() time\">%s</column>"
1240 while (!feof (fp
.get ()));
1243 buffer
+= "</osdata>\n";
1248 /* Collect data about loaded kernel modules and write it into
1252 linux_xfer_osdata_modules ()
1254 std::string buffer
= "<osdata type=\"modules\">\n";
1256 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/modules", "r");
1263 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1265 char *name
, *dependencies
, *status
, *tmp
, *saveptr
;
1267 unsigned long long address
;
1270 name
= strtok_r (buf
, " ", &saveptr
);
1274 tmp
= strtok_r (NULL
, " ", &saveptr
);
1277 if (sscanf (tmp
, "%u", &size
) != 1)
1280 tmp
= strtok_r (NULL
, " ", &saveptr
);
1283 if (sscanf (tmp
, "%d", &uses
) != 1)
1286 dependencies
= strtok_r (NULL
, " ", &saveptr
);
1287 if (dependencies
== NULL
)
1290 status
= strtok_r (NULL
, " ", &saveptr
);
1294 tmp
= strtok_r (NULL
, "\n", &saveptr
);
1297 if (sscanf (tmp
, "%llx", &address
) != 1)
1300 string_xml_appendf (buffer
,
1302 "<column name=\"name\">%s</column>"
1303 "<column name=\"size\">%u</column>"
1304 "<column name=\"num uses\">%d</column>"
1305 "<column name=\"dependencies\">%s</column>"
1306 "<column name=\"status\">%s</column>"
1307 "<column name=\"address\">%llx</column>"
1317 while (!feof (fp
.get ()));
1320 buffer
+= "</osdata>\n";
1325 static std::string
linux_xfer_osdata_info_os_types ();
1327 static struct osdata_type
{
1330 const char *description
;
1331 std::string (*take_snapshot
) ();
1333 } osdata_table
[] = {
1334 { "types", "Types", "Listing of info os types you can list",
1335 linux_xfer_osdata_info_os_types
},
1336 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1337 linux_xfer_osdata_cpus
},
1338 { "files", "File descriptors", "Listing of all file descriptors",
1339 linux_xfer_osdata_fds
},
1340 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1341 linux_xfer_osdata_modules
},
1342 { "msg", "Message queues", "Listing of all message queues",
1343 linux_xfer_osdata_msg
},
1344 { "processes", "Processes", "Listing of all processes",
1345 linux_xfer_osdata_processes
},
1346 { "procgroups", "Process groups", "Listing of all process groups",
1347 linux_xfer_osdata_processgroups
},
1348 { "semaphores", "Semaphores", "Listing of all semaphores",
1349 linux_xfer_osdata_sem
},
1350 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1351 linux_xfer_osdata_shm
},
1352 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1353 linux_xfer_osdata_isockets
},
1354 { "threads", "Threads", "Listing of all threads",
1355 linux_xfer_osdata_threads
},
1356 { NULL
, NULL
, NULL
}
1359 /* Collect data about all types info os can show in BUFFER. */
1362 linux_xfer_osdata_info_os_types ()
1364 std::string buffer
= "<osdata type=\"types\">\n";
1366 /* Start the below loop at 1, as we do not want to list ourselves. */
1367 for (int i
= 1; osdata_table
[i
].type
; ++i
)
1368 string_xml_appendf (buffer
,
1370 "<column name=\"Type\">%s</column>"
1371 "<column name=\"Description\">%s</column>"
1372 "<column name=\"Title\">%s</column>"
1374 osdata_table
[i
].type
,
1375 osdata_table
[i
].description
,
1376 osdata_table
[i
].title
);
1378 buffer
+= "</osdata>\n";
1384 /* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1385 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
1388 common_getter (struct osdata_type
*osd
,
1389 gdb_byte
*readbuf
, ULONGEST offset
, ULONGEST len
)
1391 gdb_assert (readbuf
);
1394 osd
->buffer
= osd
->take_snapshot ();
1396 if (offset
>= osd
->buffer
.size ())
1398 /* Done. Get rid of the buffer. */
1399 osd
->buffer
.clear ();
1403 len
= std::min (len
, osd
->buffer
.size () - offset
);
1404 memcpy (readbuf
, &osd
->buffer
[offset
], len
);
1411 linux_common_xfer_osdata (const char *annex
, gdb_byte
*readbuf
,
1412 ULONGEST offset
, ULONGEST len
)
1414 if (!annex
|| *annex
== '\0')
1416 return common_getter (&osdata_table
[0],
1417 readbuf
, offset
, len
);
1423 for (i
= 0; osdata_table
[i
].type
; ++i
)
1425 if (strcmp (annex
, osdata_table
[i
].type
) == 0)
1426 return common_getter (&osdata_table
[i
],
1427 readbuf
, offset
, len
);