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
];
72 sprintf (filename
, "/proc/%lld/task/%lld/stat",
73 (PID_T
) ptid
.pid (), (PID_T
) ptid
.lwp ());
74 gdb_file_up f
= gdb_fopen_cloexec (filename
, "r");
81 content
= (char *) xrealloc (content
, content_read
+ 1024);
82 n
= fread (content
+ content_read
, 1, 1024, f
.get ());
86 content
[content_read
] = '\0';
91 /* ps command also relies on no trailing fields ever contain ')'. */
92 p
= strrchr (content
, ')');
96 /* If the first field after program name has index 0, then core number is
97 the field with index 36. There's no constant for that anywhere. */
99 p
= strtok_r (p
, " ", &ts
);
100 for (i
= 0; p
!= NULL
&& i
!= 36; ++i
)
101 p
= strtok_r (NULL
, " ", &ts
);
103 if (p
== NULL
|| sscanf (p
, "%d", &core
) == 0)
111 /* Finds the command-line of process PID and copies it into COMMAND.
112 At most MAXLEN characters are copied. If the command-line cannot
113 be found, PID is copied into command in text-form. */
116 command_from_pid (char *command
, int maxlen
, PID_T pid
)
118 std::string stat_path
= string_printf ("/proc/%lld/stat", pid
);
119 gdb_file_up fp
= gdb_fopen_cloexec (stat_path
, "r");
125 /* sizeof (cmd) should be greater or equal to TASK_COMM_LEN (in
126 include/linux/sched.h in the Linux kernel sources) plus two
127 (for the brackets). */
130 int items_read
= fscanf (fp
.get (), "%lld %17s", &stat_pid
, cmd
);
132 if (items_read
== 2 && pid
== stat_pid
)
134 cmd
[strlen (cmd
) - 1] = '\0'; /* Remove trailing parenthesis. */
135 strncpy (command
, cmd
+ 1, maxlen
); /* Ignore leading parenthesis. */
140 /* Return the PID if a /proc entry for the process cannot be found. */
141 snprintf (command
, maxlen
, "%lld", pid
);
144 command
[maxlen
- 1] = '\0'; /* Ensure string is null-terminated. */
147 /* Returns the command-line of the process with the given PID. The
148 returned string needs to be freed using xfree after use. */
151 commandline_from_pid (PID_T pid
)
153 std::string pathname
= string_printf ("/proc/%lld/cmdline", pid
);
154 char *commandline
= NULL
;
155 gdb_file_up f
= gdb_fopen_cloexec (pathname
, "r");
161 while (!feof (f
.get ()))
164 size_t read_bytes
= fread (buf
, 1, sizeof (buf
), f
.get ());
168 commandline
= (char *) xrealloc (commandline
, len
+ read_bytes
+ 1);
169 memcpy (commandline
+ len
, buf
, read_bytes
);
178 /* Replace null characters with spaces. */
179 for (i
= 0; i
< len
; ++i
)
180 if (commandline
[i
] == '\0')
181 commandline
[i
] = ' ';
183 commandline
[len
] = '\0';
187 /* Return the command in square brackets if the command-line
189 commandline
= (char *) xmalloc (32);
190 commandline
[0] = '[';
191 command_from_pid (commandline
+ 1, 31, pid
);
193 len
= strlen (commandline
);
195 strcat (commandline
, "]");
202 /* Finds the user name for the user UID and copies it into USER. At
203 most MAXLEN characters are copied. */
206 user_from_uid (char *user
, int maxlen
, uid_t uid
)
208 struct passwd
*pwentry
;
211 getpwuid_r (uid
, &pwd
, buf
, sizeof (buf
), &pwentry
);
215 strncpy (user
, pwentry
->pw_name
, maxlen
- 1);
216 /* Ensure that the user name is null-terminated. */
217 user
[maxlen
- 1] = '\0';
223 /* Finds the owner of process PID and returns the user id in OWNER.
224 Returns 0 if the owner was found, -1 otherwise. */
227 get_process_owner (uid_t
*owner
, PID_T pid
)
230 char procentry
[sizeof ("/proc/") + MAX_PID_T_STRLEN
];
232 sprintf (procentry
, "/proc/%lld", pid
);
234 if (stat (procentry
, &statbuf
) == 0 && S_ISDIR (statbuf
.st_mode
))
236 *owner
= statbuf
.st_uid
;
243 /* Find the CPU cores used by process PID and return them in CORES.
244 CORES points to an array of NUM_CORES elements. */
247 get_cores_used_by_process (PID_T pid
, int *cores
, const int num_cores
)
249 char taskdir
[sizeof ("/proc/") + MAX_PID_T_STRLEN
+ sizeof ("/task") - 1];
254 sprintf (taskdir
, "/proc/%lld/task", pid
);
255 dir
= opendir (taskdir
);
258 while ((dp
= readdir (dir
)) != NULL
)
263 if (!isdigit (dp
->d_name
[0])
264 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
267 sscanf (dp
->d_name
, "%lld", &tid
);
268 core
= linux_common_core_of_thread (ptid_t ((pid_t
) pid
,
271 if (core
>= 0 && core
< num_cores
)
285 linux_xfer_osdata_processes (struct buffer
*buffer
)
289 buffer_grow_str (buffer
, "<osdata type=\"processes\">\n");
291 dirp
= opendir ("/proc");
294 const int num_cores
= sysconf (_SC_NPROCESSORS_ONLN
);
297 while ((dp
= readdir (dirp
)) != NULL
)
301 char user
[UT_NAMESIZE
];
305 std::string cores_str
;
308 if (!isdigit (dp
->d_name
[0])
309 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
312 sscanf (dp
->d_name
, "%lld", &pid
);
313 command_line
= commandline_from_pid (pid
);
315 if (get_process_owner (&owner
, pid
) == 0)
316 user_from_uid (user
, sizeof (user
), owner
);
320 /* Find CPU cores used by the process. */
321 cores
= XCNEWVEC (int, num_cores
);
322 task_count
= get_cores_used_by_process (pid
, cores
, num_cores
);
324 for (i
= 0; i
< num_cores
&& task_count
> 0; ++i
)
327 string_appendf (cores_str
, "%d", i
);
329 task_count
-= cores
[i
];
339 "<column name=\"pid\">%lld</column>"
340 "<column name=\"user\">%s</column>"
341 "<column name=\"command\">%s</column>"
342 "<column name=\"cores\">%s</column>"
346 command_line
? command_line
: "",
349 xfree (command_line
);
355 buffer_grow_str0 (buffer
, "</osdata>\n");
358 /* A simple PID/PGID pair. */
360 struct pid_pgid_entry
362 pid_pgid_entry (PID_T pid_
, PID_T pgid_
)
363 : pid (pid_
), pgid (pgid_
)
366 /* Return true if this pid is the leader of its process group. */
368 bool is_leader () const
373 bool operator< (const pid_pgid_entry
&other
) const
376 if (this->pgid
!= other
.pgid
)
377 return this->pgid
< other
.pgid
;
379 /* Process group leaders always come first... */
380 if (this->is_leader ())
382 if (!other
.is_leader ())
385 else if (other
.is_leader ())
388 /* ...else sort by PID. */
389 return this->pid
< other
.pid
;
395 /* Collect all process groups from /proc in BUFFER. */
398 linux_xfer_osdata_processgroups (struct buffer
*buffer
)
402 buffer_grow_str (buffer
, "<osdata type=\"process groups\">\n");
404 dirp
= opendir ("/proc");
407 std::vector
<pid_pgid_entry
> process_list
;
410 process_list
.reserve (512);
412 /* Build list consisting of PIDs followed by their
414 while ((dp
= readdir (dirp
)) != NULL
)
418 if (!isdigit (dp
->d_name
[0])
419 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
422 sscanf (dp
->d_name
, "%lld", &pid
);
423 pgid
= getpgid (pid
);
426 process_list
.emplace_back (pid
, pgid
);
431 /* Sort the process list. */
432 std::sort (process_list
.begin (), process_list
.end ());
434 for (const pid_pgid_entry
&entry
: process_list
)
436 PID_T pid
= entry
.pid
;
437 PID_T pgid
= entry
.pgid
;
438 char leader_command
[32];
441 command_from_pid (leader_command
, sizeof (leader_command
), pgid
);
442 command_line
= commandline_from_pid (pid
);
447 "<column name=\"pgid\">%lld</column>"
448 "<column name=\"leader command\">%s</column>"
449 "<column name=\"pid\">%lld</column>"
450 "<column name=\"command line\">%s</column>"
455 command_line
? command_line
: "");
457 xfree (command_line
);
461 buffer_grow_str0 (buffer
, "</osdata>\n");
464 /* Collect all the threads in /proc by iterating through processes and
465 then tasks within each process in BUFFER. */
468 linux_xfer_osdata_threads (struct buffer
*buffer
)
472 buffer_grow_str (buffer
, "<osdata type=\"threads\">\n");
474 dirp
= opendir ("/proc");
479 while ((dp
= readdir (dirp
)) != NULL
)
482 char procentry
[sizeof ("/proc/4294967295")];
484 if (!isdigit (dp
->d_name
[0])
485 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
488 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
490 if (stat (procentry
, &statbuf
) == 0
491 && S_ISDIR (statbuf
.st_mode
))
498 = string_printf ("/proc/%s/task", dp
->d_name
);
500 pid
= atoi (dp
->d_name
);
501 command_from_pid (command
, sizeof (command
), pid
);
503 dirp2
= opendir (pathname
.c_str ());
509 while ((dp2
= readdir (dirp2
)) != NULL
)
514 if (!isdigit (dp2
->d_name
[0])
515 || NAMELEN (dp2
) > sizeof ("4294967295") - 1)
518 tid
= atoi (dp2
->d_name
);
519 core
= linux_common_core_of_thread (ptid_t (pid
, tid
));
524 "<column name=\"pid\">%lld</column>"
525 "<column name=\"command\">%s</column>"
526 "<column name=\"tid\">%lld</column>"
527 "<column name=\"core\">%d</column>"
543 buffer_grow_str0 (buffer
, "</osdata>\n");
546 /* Collect data about the cpus/cores on the system in BUFFER. */
549 linux_xfer_osdata_cpus (struct buffer
*buffer
)
553 buffer_grow_str (buffer
, "<osdata type=\"cpus\">\n");
555 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/cpuinfo", "r");
562 if (fgets (buf
, sizeof (buf
), fp
.get ()))
568 key
= strtok_r (buf
, ":", &saveptr
);
572 value
= strtok_r (NULL
, ":", &saveptr
);
576 while (key
[i
] != '\t' && key
[i
] != '\0')
582 while (value
[i
] != '\t' && value
[i
] != '\0')
587 if (strcmp (key
, "processor") == 0)
590 buffer_grow_str (buffer
, "<item>");
592 buffer_grow_str (buffer
, "</item><item>");
597 buffer_xml_printf (buffer
,
598 "<column name=\"%s\">%s</column>",
603 while (!feof (fp
.get ()));
606 buffer_grow_str (buffer
, "</item>");
609 buffer_grow_str0 (buffer
, "</osdata>\n");
612 /* Collect all the open file descriptors found in /proc and put the details
613 found about them into BUFFER. */
616 linux_xfer_osdata_fds (struct buffer
*buffer
)
620 buffer_grow_str (buffer
, "<osdata type=\"files\">\n");
622 dirp
= opendir ("/proc");
627 while ((dp
= readdir (dirp
)) != NULL
)
630 char procentry
[sizeof ("/proc/4294967295")];
632 if (!isdigit (dp
->d_name
[0])
633 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
636 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
638 if (stat (procentry
, &statbuf
) == 0
639 && S_ISDIR (statbuf
.st_mode
))
645 pid
= atoi (dp
->d_name
);
646 command_from_pid (command
, sizeof (command
), pid
);
649 = string_printf ("/proc/%s/fd", dp
->d_name
);
650 dirp2
= opendir (pathname
.c_str ());
656 while ((dp2
= readdir (dirp2
)) != NULL
)
661 if (!isdigit (dp2
->d_name
[0]))
665 = string_printf ("%s/%s", pathname
.c_str (),
667 rslt
= readlink (fdname
.c_str (), buf
,
675 "<column name=\"pid\">%s</column>"
676 "<column name=\"command\">%s</column>"
677 "<column name=\"file descriptor\">%s</column>"
678 "<column name=\"name\">%s</column>"
683 (rslt
>= 0 ? buf
: dp2
->d_name
));
694 buffer_grow_str0 (buffer
, "</osdata>\n");
697 /* Returns the socket state STATE in textual form. */
700 format_socket_state (unsigned char state
)
702 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
719 case TCP_ESTABLISHED
:
720 return "ESTABLISHED";
749 struct sockaddr_in sin
;
750 struct sockaddr_in6 sin6
;
753 /* Auxiliary function used by linux_xfer_osdata_isocket. Formats
754 information for all open internet sockets of type FAMILY on the
755 system into BUFFER. If TCP is set, only TCP sockets are processed,
756 otherwise only UDP sockets are processed. */
759 print_sockets (unsigned short family
, int tcp
, struct buffer
*buffer
)
761 const char *proc_file
;
763 if (family
== AF_INET
)
764 proc_file
= tcp
? "/proc/net/tcp" : "/proc/net/udp";
765 else if (family
== AF_INET6
)
766 proc_file
= tcp
? "/proc/net/tcp6" : "/proc/net/udp6";
770 gdb_file_up fp
= gdb_fopen_cloexec (proc_file
, "r");
777 if (fgets (buf
, sizeof (buf
), fp
.get ()))
780 unsigned int local_port
, remote_port
, state
;
781 char local_address
[NI_MAXHOST
], remote_address
[NI_MAXHOST
];
785 #error "local_address and remote_address buffers too small"
788 result
= sscanf (buf
,
789 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
790 local_address
, &local_port
,
791 remote_address
, &remote_port
,
797 union socket_addr locaddr
, remaddr
;
799 char user
[UT_NAMESIZE
];
800 char local_service
[NI_MAXSERV
], remote_service
[NI_MAXSERV
];
802 if (family
== AF_INET
)
804 sscanf (local_address
, "%X",
805 &locaddr
.sin
.sin_addr
.s_addr
);
806 sscanf (remote_address
, "%X",
807 &remaddr
.sin
.sin_addr
.s_addr
);
809 locaddr
.sin
.sin_port
= htons (local_port
);
810 remaddr
.sin
.sin_port
= htons (remote_port
);
812 addr_size
= sizeof (struct sockaddr_in
);
816 sscanf (local_address
, "%8X%8X%8X%8X",
817 locaddr
.sin6
.sin6_addr
.s6_addr32
,
818 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
819 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
820 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
821 sscanf (remote_address
, "%8X%8X%8X%8X",
822 remaddr
.sin6
.sin6_addr
.s6_addr32
,
823 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
824 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
825 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
827 locaddr
.sin6
.sin6_port
= htons (local_port
);
828 remaddr
.sin6
.sin6_port
= htons (remote_port
);
830 locaddr
.sin6
.sin6_flowinfo
= 0;
831 remaddr
.sin6
.sin6_flowinfo
= 0;
832 locaddr
.sin6
.sin6_scope_id
= 0;
833 remaddr
.sin6
.sin6_scope_id
= 0;
835 addr_size
= sizeof (struct sockaddr_in6
);
838 locaddr
.sa
.sa_family
= remaddr
.sa
.sa_family
= family
;
840 result
= getnameinfo (&locaddr
.sa
, addr_size
,
841 local_address
, sizeof (local_address
),
842 local_service
, sizeof (local_service
),
843 NI_NUMERICHOST
| NI_NUMERICSERV
844 | (tcp
? 0 : NI_DGRAM
));
848 result
= getnameinfo (&remaddr
.sa
, addr_size
,
850 sizeof (remote_address
),
852 sizeof (remote_service
),
853 NI_NUMERICHOST
| NI_NUMERICSERV
854 | (tcp
? 0 : NI_DGRAM
));
858 user_from_uid (user
, sizeof (user
), uid
);
863 "<column name=\"local address\">%s</column>"
864 "<column name=\"local port\">%s</column>"
865 "<column name=\"remote address\">%s</column>"
866 "<column name=\"remote port\">%s</column>"
867 "<column name=\"state\">%s</column>"
868 "<column name=\"user\">%s</column>"
869 "<column name=\"family\">%s</column>"
870 "<column name=\"protocol\">%s</column>"
876 format_socket_state (state
),
878 (family
== AF_INET
) ? "INET" : "INET6",
879 tcp
? "STREAM" : "DGRAM");
883 while (!feof (fp
.get ()));
887 /* Collect data about internet sockets and write it into BUFFER. */
890 linux_xfer_osdata_isockets (struct buffer
*buffer
)
892 buffer_grow_str (buffer
, "<osdata type=\"I sockets\">\n");
894 print_sockets (AF_INET
, 1, buffer
);
895 print_sockets (AF_INET
, 0, buffer
);
896 print_sockets (AF_INET6
, 1, buffer
);
897 print_sockets (AF_INET6
, 0, buffer
);
899 buffer_grow_str0 (buffer
, "</osdata>\n");
902 /* Converts the time SECONDS into textual form and copies it into a
903 buffer TIME, with at most MAXLEN characters copied. */
906 time_from_time_t (char *time
, int maxlen
, TIME_T seconds
)
912 time_t t
= (time_t) seconds
;
914 /* Per the ctime_r manpage, this buffer needs to be at least 26
917 const char *time_str
= ctime_r (&t
, buf
);
918 strncpy (time
, time_str
, maxlen
- 1);
919 time
[maxlen
- 1] = '\0';
923 /* Finds the group name for the group GID and copies it into GROUP.
924 At most MAXLEN characters are copied. */
927 group_from_gid (char *group
, int maxlen
, gid_t gid
)
929 struct group
*grentry
= getgrgid (gid
);
933 strncpy (group
, grentry
->gr_name
, maxlen
- 1);
934 /* Ensure that the group name is null-terminated. */
935 group
[maxlen
- 1] = '\0';
941 /* Collect data about shared memory recorded in /proc and write it
945 linux_xfer_osdata_shm (struct buffer
*buffer
)
947 buffer_grow_str (buffer
, "<osdata type=\"shared memory\">\n");
949 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
956 if (fgets (buf
, sizeof (buf
), fp
.get ()))
962 int shmid
, size
, nattch
;
963 TIME_T atime
, dtime
, ctime
;
967 items_read
= sscanf (buf
,
968 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
969 &key
, &shmid
, &perms
, &size
,
972 &uid
, &gid
, &cuid
, &cgid
,
973 &atime
, &dtime
, &ctime
);
975 if (items_read
== 14)
977 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
978 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
979 char ccmd
[32], lcmd
[32];
980 char atime_str
[32], dtime_str
[32], ctime_str
[32];
982 user_from_uid (user
, sizeof (user
), uid
);
983 group_from_gid (group
, sizeof (group
), gid
);
984 user_from_uid (cuser
, sizeof (cuser
), cuid
);
985 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
987 command_from_pid (ccmd
, sizeof (ccmd
), cpid
);
988 command_from_pid (lcmd
, sizeof (lcmd
), lpid
);
990 time_from_time_t (atime_str
, sizeof (atime_str
), atime
);
991 time_from_time_t (dtime_str
, sizeof (dtime_str
), dtime
);
992 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
997 "<column name=\"key\">%d</column>"
998 "<column name=\"shmid\">%d</column>"
999 "<column name=\"permissions\">%o</column>"
1000 "<column name=\"size\">%d</column>"
1001 "<column name=\"creator command\">%s</column>"
1002 "<column name=\"last op. command\">%s</column>"
1003 "<column name=\"num attached\">%d</column>"
1004 "<column name=\"user\">%s</column>"
1005 "<column name=\"group\">%s</column>"
1006 "<column name=\"creator user\">%s</column>"
1007 "<column name=\"creator group\">%s</column>"
1008 "<column name=\"last shmat() time\">%s</column>"
1009 "<column name=\"last shmdt() time\">%s</column>"
1010 "<column name=\"last shmctl() time\">%s</column>"
1029 while (!feof (fp
.get ()));
1032 buffer_grow_str0 (buffer
, "</osdata>\n");
1035 /* Collect data about semaphores recorded in /proc and write it
1039 linux_xfer_osdata_sem (struct buffer
*buffer
)
1041 buffer_grow_str (buffer
, "<osdata type=\"semaphores\">\n");
1043 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1050 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1055 unsigned int perms
, nsems
;
1057 TIME_T otime
, ctime
;
1060 items_read
= sscanf (buf
,
1061 "%d %d %o %u %d %d %d %d %lld %lld",
1062 &key
, &semid
, &perms
, &nsems
,
1063 &uid
, &gid
, &cuid
, &cgid
,
1066 if (items_read
== 10)
1068 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1069 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1070 char otime_str
[32], ctime_str
[32];
1072 user_from_uid (user
, sizeof (user
), uid
);
1073 group_from_gid (group
, sizeof (group
), gid
);
1074 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1075 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1077 time_from_time_t (otime_str
, sizeof (otime_str
), otime
);
1078 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1083 "<column name=\"key\">%d</column>"
1084 "<column name=\"semid\">%d</column>"
1085 "<column name=\"permissions\">%o</column>"
1086 "<column name=\"num semaphores\">%u</column>"
1087 "<column name=\"user\">%s</column>"
1088 "<column name=\"group\">%s</column>"
1089 "<column name=\"creator user\">%s</column>"
1090 "<column name=\"creator group\">%s</column>"
1091 "<column name=\"last semop() time\">%s</column>"
1092 "<column name=\"last semctl() time\">%s</column>"
1107 while (!feof (fp
.get ()));
1110 buffer_grow_str0 (buffer
, "</osdata>\n");
1113 /* Collect data about message queues recorded in /proc and write it
1117 linux_xfer_osdata_msg (struct buffer
*buffer
)
1119 buffer_grow_str (buffer
, "<osdata type=\"message queues\">\n");
1121 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1128 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1134 unsigned int perms
, cbytes
, qnum
;
1136 TIME_T stime
, rtime
, ctime
;
1139 items_read
= sscanf (buf
,
1140 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1141 &key
, &msqid
, &perms
, &cbytes
, &qnum
,
1142 &lspid
, &lrpid
, &uid
, &gid
, &cuid
, &cgid
,
1143 &stime
, &rtime
, &ctime
);
1145 if (items_read
== 14)
1147 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1148 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1149 char lscmd
[32], lrcmd
[32];
1150 char stime_str
[32], rtime_str
[32], ctime_str
[32];
1152 user_from_uid (user
, sizeof (user
), uid
);
1153 group_from_gid (group
, sizeof (group
), gid
);
1154 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1155 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1157 command_from_pid (lscmd
, sizeof (lscmd
), lspid
);
1158 command_from_pid (lrcmd
, sizeof (lrcmd
), lrpid
);
1160 time_from_time_t (stime_str
, sizeof (stime_str
), stime
);
1161 time_from_time_t (rtime_str
, sizeof (rtime_str
), rtime
);
1162 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1167 "<column name=\"key\">%d</column>"
1168 "<column name=\"msqid\">%d</column>"
1169 "<column name=\"permissions\">%o</column>"
1170 "<column name=\"num used bytes\">%u</column>"
1171 "<column name=\"num messages\">%u</column>"
1172 "<column name=\"last msgsnd() command\">%s</column>"
1173 "<column name=\"last msgrcv() command\">%s</column>"
1174 "<column name=\"user\">%s</column>"
1175 "<column name=\"group\">%s</column>"
1176 "<column name=\"creator user\">%s</column>"
1177 "<column name=\"creator group\">%s</column>"
1178 "<column name=\"last msgsnd() time\">%s</column>"
1179 "<column name=\"last msgrcv() time\">%s</column>"
1180 "<column name=\"last msgctl() time\">%s</column>"
1199 while (!feof (fp
.get ()));
1202 buffer_grow_str0 (buffer
, "</osdata>\n");
1205 /* Collect data about loaded kernel modules and write it into
1209 linux_xfer_osdata_modules (struct buffer
*buffer
)
1211 buffer_grow_str (buffer
, "<osdata type=\"modules\">\n");
1213 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/modules", "r");
1220 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1222 char *name
, *dependencies
, *status
, *tmp
, *saveptr
;
1224 unsigned long long address
;
1227 name
= strtok_r (buf
, " ", &saveptr
);
1231 tmp
= strtok_r (NULL
, " ", &saveptr
);
1234 if (sscanf (tmp
, "%u", &size
) != 1)
1237 tmp
= strtok_r (NULL
, " ", &saveptr
);
1240 if (sscanf (tmp
, "%d", &uses
) != 1)
1243 dependencies
= strtok_r (NULL
, " ", &saveptr
);
1244 if (dependencies
== NULL
)
1247 status
= strtok_r (NULL
, " ", &saveptr
);
1251 tmp
= strtok_r (NULL
, "\n", &saveptr
);
1254 if (sscanf (tmp
, "%llx", &address
) != 1)
1257 buffer_xml_printf (buffer
,
1259 "<column name=\"name\">%s</column>"
1260 "<column name=\"size\">%u</column>"
1261 "<column name=\"num uses\">%d</column>"
1262 "<column name=\"dependencies\">%s</column>"
1263 "<column name=\"status\">%s</column>"
1264 "<column name=\"address\">%llx</column>"
1274 while (!feof (fp
.get ()));
1277 buffer_grow_str0 (buffer
, "</osdata>\n");
1280 static void linux_xfer_osdata_info_os_types (struct buffer
*buffer
);
1282 static struct osdata_type
{
1285 const char *description
;
1286 void (*take_snapshot
) (struct buffer
*buffer
);
1288 struct buffer buffer
;
1289 } osdata_table
[] = {
1290 { "types", "Types", "Listing of info os types you can list",
1291 linux_xfer_osdata_info_os_types
, -1 },
1292 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1293 linux_xfer_osdata_cpus
, -1 },
1294 { "files", "File descriptors", "Listing of all file descriptors",
1295 linux_xfer_osdata_fds
, -1 },
1296 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1297 linux_xfer_osdata_modules
, -1 },
1298 { "msg", "Message queues", "Listing of all message queues",
1299 linux_xfer_osdata_msg
, -1 },
1300 { "processes", "Processes", "Listing of all processes",
1301 linux_xfer_osdata_processes
, -1 },
1302 { "procgroups", "Process groups", "Listing of all process groups",
1303 linux_xfer_osdata_processgroups
, -1 },
1304 { "semaphores", "Semaphores", "Listing of all semaphores",
1305 linux_xfer_osdata_sem
, -1 },
1306 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1307 linux_xfer_osdata_shm
, -1 },
1308 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1309 linux_xfer_osdata_isockets
, -1 },
1310 { "threads", "Threads", "Listing of all threads",
1311 linux_xfer_osdata_threads
, -1 },
1312 { NULL
, NULL
, NULL
}
1315 /* Collect data about all types info os can show in BUFFER. */
1318 linux_xfer_osdata_info_os_types (struct buffer
*buffer
)
1320 buffer_grow_str (buffer
, "<osdata type=\"types\">\n");
1322 /* Start the below loop at 1, as we do not want to list ourselves. */
1323 for (int i
= 1; osdata_table
[i
].type
; ++i
)
1324 buffer_xml_printf (buffer
,
1326 "<column name=\"Type\">%s</column>"
1327 "<column name=\"Description\">%s</column>"
1328 "<column name=\"Title\">%s</column>"
1330 osdata_table
[i
].type
,
1331 osdata_table
[i
].description
,
1332 osdata_table
[i
].title
);
1334 buffer_grow_str0 (buffer
, "</osdata>\n");
1338 /* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1339 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
1342 common_getter (struct osdata_type
*osd
,
1343 gdb_byte
*readbuf
, ULONGEST offset
, ULONGEST len
)
1345 gdb_assert (readbuf
);
1349 if (osd
->len_avail
!= -1 && osd
->len_avail
!= 0)
1350 buffer_free (&osd
->buffer
);
1352 buffer_init (&osd
->buffer
);
1353 (osd
->take_snapshot
) (&osd
->buffer
);
1354 osd
->len_avail
= strlen (osd
->buffer
.buffer
);
1356 if (offset
>= osd
->len_avail
)
1358 /* Done. Get rid of the buffer. */
1359 buffer_free (&osd
->buffer
);
1363 if (len
> osd
->len_avail
- offset
)
1364 len
= osd
->len_avail
- offset
;
1365 memcpy (readbuf
, osd
->buffer
.buffer
+ offset
, len
);
1372 linux_common_xfer_osdata (const char *annex
, gdb_byte
*readbuf
,
1373 ULONGEST offset
, ULONGEST len
)
1375 if (!annex
|| *annex
== '\0')
1377 return common_getter (&osdata_table
[0],
1378 readbuf
, offset
, len
);
1384 for (i
= 0; osdata_table
[i
].type
; ++i
)
1386 if (strcmp (annex
, osdata_table
[i
].type
) == 0)
1387 return common_getter (&osdata_table
[i
],
1388 readbuf
, offset
, len
);