1 /* Linux-specific functions to retrieve OS data.
3 Copyright (C) 2009-2019 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 "common/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 "common/xml-utils.h"
36 #include "common/buffer.h"
39 #include "common/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
= getpwuid (uid
);
212 strncpy (user
, pwentry
->pw_name
, maxlen
);
213 /* Ensure that the user name is null-terminated. */
214 user
[maxlen
- 1] = '\0';
220 /* Finds the owner of process PID and returns the user id in OWNER.
221 Returns 0 if the owner was found, -1 otherwise. */
224 get_process_owner (uid_t
*owner
, PID_T pid
)
227 char procentry
[sizeof ("/proc/") + MAX_PID_T_STRLEN
];
229 sprintf (procentry
, "/proc/%lld", pid
);
231 if (stat (procentry
, &statbuf
) == 0 && S_ISDIR (statbuf
.st_mode
))
233 *owner
= statbuf
.st_uid
;
240 /* Find the CPU cores used by process PID and return them in CORES.
241 CORES points to an array of NUM_CORES elements. */
244 get_cores_used_by_process (PID_T pid
, int *cores
, const int num_cores
)
246 char taskdir
[sizeof ("/proc/") + MAX_PID_T_STRLEN
+ sizeof ("/task") - 1];
251 sprintf (taskdir
, "/proc/%lld/task", pid
);
252 dir
= opendir (taskdir
);
255 while ((dp
= readdir (dir
)) != NULL
)
260 if (!isdigit (dp
->d_name
[0])
261 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
264 sscanf (dp
->d_name
, "%lld", &tid
);
265 core
= linux_common_core_of_thread (ptid_t ((pid_t
) pid
,
268 if (core
>= 0 && core
< num_cores
)
282 linux_xfer_osdata_processes (struct buffer
*buffer
)
286 buffer_grow_str (buffer
, "<osdata type=\"processes\">\n");
288 dirp
= opendir ("/proc");
291 const int num_cores
= sysconf (_SC_NPROCESSORS_ONLN
);
294 while ((dp
= readdir (dirp
)) != NULL
)
298 char user
[UT_NAMESIZE
];
305 if (!isdigit (dp
->d_name
[0])
306 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
309 sscanf (dp
->d_name
, "%lld", &pid
);
310 command_line
= commandline_from_pid (pid
);
312 if (get_process_owner (&owner
, pid
) == 0)
313 user_from_uid (user
, sizeof (user
), owner
);
317 /* Find CPU cores used by the process. */
318 cores
= XCNEWVEC (int, num_cores
);
319 task_count
= get_cores_used_by_process (pid
, cores
, num_cores
);
320 cores_str
= (char *) xcalloc (task_count
, sizeof ("4294967295") + 1);
322 for (i
= 0; i
< num_cores
&& task_count
> 0; ++i
)
325 char core_str
[sizeof ("4294967295")];
327 sprintf (core_str
, "%d", i
);
328 strcat (cores_str
, core_str
);
330 task_count
-= cores
[i
];
332 strcat (cores_str
, ",");
340 "<column name=\"pid\">%lld</column>"
341 "<column name=\"user\">%s</column>"
342 "<column name=\"command\">%s</column>"
343 "<column name=\"cores\">%s</column>"
347 command_line
? command_line
: "",
350 xfree (command_line
);
357 buffer_grow_str0 (buffer
, "</osdata>\n");
360 /* A simple PID/PGID pair. */
362 struct pid_pgid_entry
364 pid_pgid_entry (PID_T pid_
, PID_T pgid_
)
365 : pid (pid_
), pgid (pgid_
)
368 /* Return true if this pid is the leader of its process group. */
370 bool is_leader () const
375 bool operator< (const pid_pgid_entry
&other
) const
378 if (this->pgid
!= other
.pgid
)
379 return this->pgid
< other
.pgid
;
381 /* Process group leaders always come first... */
382 if (this->is_leader ())
384 if (!other
.is_leader ())
387 else if (other
.is_leader ())
390 /* ...else sort by PID. */
391 return this->pid
< other
.pid
;
397 /* Collect all process groups from /proc in BUFFER. */
400 linux_xfer_osdata_processgroups (struct buffer
*buffer
)
404 buffer_grow_str (buffer
, "<osdata type=\"process groups\">\n");
406 dirp
= opendir ("/proc");
409 std::vector
<pid_pgid_entry
> process_list
;
412 process_list
.reserve (512);
414 /* Build list consisting of PIDs followed by their
416 while ((dp
= readdir (dirp
)) != NULL
)
420 if (!isdigit (dp
->d_name
[0])
421 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
424 sscanf (dp
->d_name
, "%lld", &pid
);
425 pgid
= getpgid (pid
);
428 process_list
.emplace_back (pid
, pgid
);
433 /* Sort the process list. */
434 std::sort (process_list
.begin (), process_list
.end ());
436 for (const pid_pgid_entry
&entry
: process_list
)
438 PID_T pid
= entry
.pid
;
439 PID_T pgid
= entry
.pgid
;
440 char leader_command
[32];
443 command_from_pid (leader_command
, sizeof (leader_command
), pgid
);
444 command_line
= commandline_from_pid (pid
);
449 "<column name=\"pgid\">%lld</column>"
450 "<column name=\"leader command\">%s</column>"
451 "<column name=\"pid\">%lld</column>"
452 "<column name=\"command line\">%s</column>"
457 command_line
? command_line
: "");
459 xfree (command_line
);
463 buffer_grow_str0 (buffer
, "</osdata>\n");
466 /* Collect all the threads in /proc by iterating through processes and
467 then tasks within each process in BUFFER. */
470 linux_xfer_osdata_threads (struct buffer
*buffer
)
474 buffer_grow_str (buffer
, "<osdata type=\"threads\">\n");
476 dirp
= opendir ("/proc");
481 while ((dp
= readdir (dirp
)) != NULL
)
484 char procentry
[sizeof ("/proc/4294967295")];
486 if (!isdigit (dp
->d_name
[0])
487 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
490 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
492 if (stat (procentry
, &statbuf
) == 0
493 && S_ISDIR (statbuf
.st_mode
))
500 = string_printf ("/proc/%s/task", dp
->d_name
);
502 pid
= atoi (dp
->d_name
);
503 command_from_pid (command
, sizeof (command
), pid
);
505 dirp2
= opendir (pathname
.c_str ());
511 while ((dp2
= readdir (dirp2
)) != NULL
)
516 if (!isdigit (dp2
->d_name
[0])
517 || NAMELEN (dp2
) > sizeof ("4294967295") - 1)
520 tid
= atoi (dp2
->d_name
);
521 core
= linux_common_core_of_thread (ptid_t (pid
, tid
, 0));
526 "<column name=\"pid\">%lld</column>"
527 "<column name=\"command\">%s</column>"
528 "<column name=\"tid\">%lld</column>"
529 "<column name=\"core\">%d</column>"
545 buffer_grow_str0 (buffer
, "</osdata>\n");
548 /* Collect data about the cpus/cores on the system in BUFFER. */
551 linux_xfer_osdata_cpus (struct buffer
*buffer
)
555 buffer_grow_str (buffer
, "<osdata type=\"cpus\">\n");
557 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/cpuinfo", "r");
564 if (fgets (buf
, sizeof (buf
), fp
.get ()))
569 key
= strtok (buf
, ":");
573 value
= strtok (NULL
, ":");
577 while (key
[i
] != '\t' && key
[i
] != '\0')
583 while (value
[i
] != '\t' && value
[i
] != '\0')
588 if (strcmp (key
, "processor") == 0)
591 buffer_grow_str (buffer
, "<item>");
593 buffer_grow_str (buffer
, "</item><item>");
598 buffer_xml_printf (buffer
,
599 "<column name=\"%s\">%s</column>",
604 while (!feof (fp
.get ()));
607 buffer_grow_str (buffer
, "</item>");
610 buffer_grow_str0 (buffer
, "</osdata>\n");
613 /* Collect all the open file descriptors found in /proc and put the details
614 found about them into BUFFER. */
617 linux_xfer_osdata_fds (struct buffer
*buffer
)
621 buffer_grow_str (buffer
, "<osdata type=\"files\">\n");
623 dirp
= opendir ("/proc");
628 while ((dp
= readdir (dirp
)) != NULL
)
631 char procentry
[sizeof ("/proc/4294967295")];
633 if (!isdigit (dp
->d_name
[0])
634 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
637 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
639 if (stat (procentry
, &statbuf
) == 0
640 && S_ISDIR (statbuf
.st_mode
))
646 pid
= atoi (dp
->d_name
);
647 command_from_pid (command
, sizeof (command
), pid
);
650 = string_printf ("/proc/%s/fd", dp
->d_name
);
651 dirp2
= opendir (pathname
.c_str ());
657 while ((dp2
= readdir (dirp2
)) != NULL
)
662 if (!isdigit (dp2
->d_name
[0]))
666 = string_printf ("%s/%s", pathname
.c_str (),
668 rslt
= readlink (fdname
.c_str (), buf
,
676 "<column name=\"pid\">%s</column>"
677 "<column name=\"command\">%s</column>"
678 "<column name=\"file descriptor\">%s</column>"
679 "<column name=\"name\">%s</column>"
684 (rslt
>= 0 ? buf
: dp2
->d_name
));
695 buffer_grow_str0 (buffer
, "</osdata>\n");
698 /* Returns the socket state STATE in textual form. */
701 format_socket_state (unsigned char state
)
703 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
720 case TCP_ESTABLISHED
:
721 return "ESTABLISHED";
750 struct sockaddr_in sin
;
751 struct sockaddr_in6 sin6
;
754 /* Auxiliary function used by linux_xfer_osdata_isocket. Formats
755 information for all open internet sockets of type FAMILY on the
756 system into BUFFER. If TCP is set, only TCP sockets are processed,
757 otherwise only UDP sockets are processed. */
760 print_sockets (unsigned short family
, int tcp
, struct buffer
*buffer
)
762 const char *proc_file
;
764 if (family
== AF_INET
)
765 proc_file
= tcp
? "/proc/net/tcp" : "/proc/net/udp";
766 else if (family
== AF_INET6
)
767 proc_file
= tcp
? "/proc/net/tcp6" : "/proc/net/udp6";
771 gdb_file_up fp
= gdb_fopen_cloexec (proc_file
, "r");
778 if (fgets (buf
, sizeof (buf
), fp
.get ()))
781 unsigned int local_port
, remote_port
, state
;
782 char local_address
[NI_MAXHOST
], remote_address
[NI_MAXHOST
];
786 #error "local_address and remote_address buffers too small"
789 result
= sscanf (buf
,
790 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
791 local_address
, &local_port
,
792 remote_address
, &remote_port
,
798 union socket_addr locaddr
, remaddr
;
800 char user
[UT_NAMESIZE
];
801 char local_service
[NI_MAXSERV
], remote_service
[NI_MAXSERV
];
803 if (family
== AF_INET
)
805 sscanf (local_address
, "%X",
806 &locaddr
.sin
.sin_addr
.s_addr
);
807 sscanf (remote_address
, "%X",
808 &remaddr
.sin
.sin_addr
.s_addr
);
810 locaddr
.sin
.sin_port
= htons (local_port
);
811 remaddr
.sin
.sin_port
= htons (remote_port
);
813 addr_size
= sizeof (struct sockaddr_in
);
817 sscanf (local_address
, "%8X%8X%8X%8X",
818 locaddr
.sin6
.sin6_addr
.s6_addr32
,
819 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
820 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
821 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
822 sscanf (remote_address
, "%8X%8X%8X%8X",
823 remaddr
.sin6
.sin6_addr
.s6_addr32
,
824 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
825 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
826 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
828 locaddr
.sin6
.sin6_port
= htons (local_port
);
829 remaddr
.sin6
.sin6_port
= htons (remote_port
);
831 locaddr
.sin6
.sin6_flowinfo
= 0;
832 remaddr
.sin6
.sin6_flowinfo
= 0;
833 locaddr
.sin6
.sin6_scope_id
= 0;
834 remaddr
.sin6
.sin6_scope_id
= 0;
836 addr_size
= sizeof (struct sockaddr_in6
);
839 locaddr
.sa
.sa_family
= remaddr
.sa
.sa_family
= family
;
841 result
= getnameinfo (&locaddr
.sa
, addr_size
,
842 local_address
, sizeof (local_address
),
843 local_service
, sizeof (local_service
),
844 NI_NUMERICHOST
| NI_NUMERICSERV
845 | (tcp
? 0 : NI_DGRAM
));
849 result
= getnameinfo (&remaddr
.sa
, addr_size
,
851 sizeof (remote_address
),
853 sizeof (remote_service
),
854 NI_NUMERICHOST
| NI_NUMERICSERV
855 | (tcp
? 0 : NI_DGRAM
));
859 user_from_uid (user
, sizeof (user
), uid
);
864 "<column name=\"local address\">%s</column>"
865 "<column name=\"local port\">%s</column>"
866 "<column name=\"remote address\">%s</column>"
867 "<column name=\"remote port\">%s</column>"
868 "<column name=\"state\">%s</column>"
869 "<column name=\"user\">%s</column>"
870 "<column name=\"family\">%s</column>"
871 "<column name=\"protocol\">%s</column>"
877 format_socket_state (state
),
879 (family
== AF_INET
) ? "INET" : "INET6",
880 tcp
? "STREAM" : "DGRAM");
884 while (!feof (fp
.get ()));
888 /* Collect data about internet sockets and write it into BUFFER. */
891 linux_xfer_osdata_isockets (struct buffer
*buffer
)
893 buffer_grow_str (buffer
, "<osdata type=\"I sockets\">\n");
895 print_sockets (AF_INET
, 1, buffer
);
896 print_sockets (AF_INET
, 0, buffer
);
897 print_sockets (AF_INET6
, 1, buffer
);
898 print_sockets (AF_INET6
, 0, buffer
);
900 buffer_grow_str0 (buffer
, "</osdata>\n");
903 /* Converts the time SECONDS into textual form and copies it into a
904 buffer TIME, with at most MAXLEN characters copied. */
907 time_from_time_t (char *time
, int maxlen
, TIME_T seconds
)
913 time_t t
= (time_t) seconds
;
915 strncpy (time
, ctime (&t
), maxlen
);
916 time
[maxlen
- 1] = '\0';
920 /* Finds the group name for the group GID and copies it into GROUP.
921 At most MAXLEN characters are copied. */
924 group_from_gid (char *group
, int maxlen
, gid_t gid
)
926 struct group
*grentry
= getgrgid (gid
);
930 strncpy (group
, grentry
->gr_name
, maxlen
);
931 /* Ensure that the group name is null-terminated. */
932 group
[maxlen
- 1] = '\0';
938 /* Collect data about shared memory recorded in /proc and write it
942 linux_xfer_osdata_shm (struct buffer
*buffer
)
944 buffer_grow_str (buffer
, "<osdata type=\"shared memory\">\n");
946 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
953 if (fgets (buf
, sizeof (buf
), fp
.get ()))
959 int shmid
, size
, nattch
;
960 TIME_T atime
, dtime
, ctime
;
964 items_read
= sscanf (buf
,
965 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
966 &key
, &shmid
, &perms
, &size
,
969 &uid
, &gid
, &cuid
, &cgid
,
970 &atime
, &dtime
, &ctime
);
972 if (items_read
== 14)
974 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
975 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
976 char ccmd
[32], lcmd
[32];
977 char atime_str
[32], dtime_str
[32], ctime_str
[32];
979 user_from_uid (user
, sizeof (user
), uid
);
980 group_from_gid (group
, sizeof (group
), gid
);
981 user_from_uid (cuser
, sizeof (cuser
), cuid
);
982 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
984 command_from_pid (ccmd
, sizeof (ccmd
), cpid
);
985 command_from_pid (lcmd
, sizeof (lcmd
), lpid
);
987 time_from_time_t (atime_str
, sizeof (atime_str
), atime
);
988 time_from_time_t (dtime_str
, sizeof (dtime_str
), dtime
);
989 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
994 "<column name=\"key\">%d</column>"
995 "<column name=\"shmid\">%d</column>"
996 "<column name=\"permissions\">%o</column>"
997 "<column name=\"size\">%d</column>"
998 "<column name=\"creator command\">%s</column>"
999 "<column name=\"last op. command\">%s</column>"
1000 "<column name=\"num attached\">%d</column>"
1001 "<column name=\"user\">%s</column>"
1002 "<column name=\"group\">%s</column>"
1003 "<column name=\"creator user\">%s</column>"
1004 "<column name=\"creator group\">%s</column>"
1005 "<column name=\"last shmat() time\">%s</column>"
1006 "<column name=\"last shmdt() time\">%s</column>"
1007 "<column name=\"last shmctl() time\">%s</column>"
1026 while (!feof (fp
.get ()));
1029 buffer_grow_str0 (buffer
, "</osdata>\n");
1032 /* Collect data about semaphores recorded in /proc and write it
1036 linux_xfer_osdata_sem (struct buffer
*buffer
)
1038 buffer_grow_str (buffer
, "<osdata type=\"semaphores\">\n");
1040 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1047 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1052 unsigned int perms
, nsems
;
1054 TIME_T otime
, ctime
;
1057 items_read
= sscanf (buf
,
1058 "%d %d %o %u %d %d %d %d %lld %lld",
1059 &key
, &semid
, &perms
, &nsems
,
1060 &uid
, &gid
, &cuid
, &cgid
,
1063 if (items_read
== 10)
1065 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1066 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1067 char otime_str
[32], ctime_str
[32];
1069 user_from_uid (user
, sizeof (user
), uid
);
1070 group_from_gid (group
, sizeof (group
), gid
);
1071 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1072 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1074 time_from_time_t (otime_str
, sizeof (otime_str
), otime
);
1075 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1080 "<column name=\"key\">%d</column>"
1081 "<column name=\"semid\">%d</column>"
1082 "<column name=\"permissions\">%o</column>"
1083 "<column name=\"num semaphores\">%u</column>"
1084 "<column name=\"user\">%s</column>"
1085 "<column name=\"group\">%s</column>"
1086 "<column name=\"creator user\">%s</column>"
1087 "<column name=\"creator group\">%s</column>"
1088 "<column name=\"last semop() time\">%s</column>"
1089 "<column name=\"last semctl() time\">%s</column>"
1104 while (!feof (fp
.get ()));
1107 buffer_grow_str0 (buffer
, "</osdata>\n");
1110 /* Collect data about message queues recorded in /proc and write it
1114 linux_xfer_osdata_msg (struct buffer
*buffer
)
1116 buffer_grow_str (buffer
, "<osdata type=\"message queues\">\n");
1118 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1125 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1131 unsigned int perms
, cbytes
, qnum
;
1133 TIME_T stime
, rtime
, ctime
;
1136 items_read
= sscanf (buf
,
1137 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1138 &key
, &msqid
, &perms
, &cbytes
, &qnum
,
1139 &lspid
, &lrpid
, &uid
, &gid
, &cuid
, &cgid
,
1140 &stime
, &rtime
, &ctime
);
1142 if (items_read
== 14)
1144 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1145 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1146 char lscmd
[32], lrcmd
[32];
1147 char stime_str
[32], rtime_str
[32], ctime_str
[32];
1149 user_from_uid (user
, sizeof (user
), uid
);
1150 group_from_gid (group
, sizeof (group
), gid
);
1151 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1152 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1154 command_from_pid (lscmd
, sizeof (lscmd
), lspid
);
1155 command_from_pid (lrcmd
, sizeof (lrcmd
), lrpid
);
1157 time_from_time_t (stime_str
, sizeof (stime_str
), stime
);
1158 time_from_time_t (rtime_str
, sizeof (rtime_str
), rtime
);
1159 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1164 "<column name=\"key\">%d</column>"
1165 "<column name=\"msqid\">%d</column>"
1166 "<column name=\"permissions\">%o</column>"
1167 "<column name=\"num used bytes\">%u</column>"
1168 "<column name=\"num messages\">%u</column>"
1169 "<column name=\"last msgsnd() command\">%s</column>"
1170 "<column name=\"last msgrcv() command\">%s</column>"
1171 "<column name=\"user\">%s</column>"
1172 "<column name=\"group\">%s</column>"
1173 "<column name=\"creator user\">%s</column>"
1174 "<column name=\"creator group\">%s</column>"
1175 "<column name=\"last msgsnd() time\">%s</column>"
1176 "<column name=\"last msgrcv() time\">%s</column>"
1177 "<column name=\"last msgctl() time\">%s</column>"
1196 while (!feof (fp
.get ()));
1199 buffer_grow_str0 (buffer
, "</osdata>\n");
1202 /* Collect data about loaded kernel modules and write it into
1206 linux_xfer_osdata_modules (struct buffer
*buffer
)
1208 buffer_grow_str (buffer
, "<osdata type=\"modules\">\n");
1210 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/modules", "r");
1217 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1219 char *name
, *dependencies
, *status
, *tmp
;
1221 unsigned long long address
;
1224 name
= strtok (buf
, " ");
1228 tmp
= strtok (NULL
, " ");
1231 if (sscanf (tmp
, "%u", &size
) != 1)
1234 tmp
= strtok (NULL
, " ");
1237 if (sscanf (tmp
, "%d", &uses
) != 1)
1240 dependencies
= strtok (NULL
, " ");
1241 if (dependencies
== NULL
)
1244 status
= strtok (NULL
, " ");
1248 tmp
= strtok (NULL
, "\n");
1251 if (sscanf (tmp
, "%llx", &address
) != 1)
1254 buffer_xml_printf (buffer
,
1256 "<column name=\"name\">%s</column>"
1257 "<column name=\"size\">%u</column>"
1258 "<column name=\"num uses\">%d</column>"
1259 "<column name=\"dependencies\">%s</column>"
1260 "<column name=\"status\">%s</column>"
1261 "<column name=\"address\">%llx</column>"
1271 while (!feof (fp
.get ()));
1274 buffer_grow_str0 (buffer
, "</osdata>\n");
1277 static void linux_xfer_osdata_info_os_types (struct buffer
*buffer
);
1279 struct osdata_type
{
1282 const char *description
;
1283 void (*take_snapshot
) (struct buffer
*buffer
);
1285 struct buffer buffer
;
1286 } osdata_table
[] = {
1287 { "types", "Types", "Listing of info os types you can list",
1288 linux_xfer_osdata_info_os_types
, -1 },
1289 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1290 linux_xfer_osdata_cpus
, -1 },
1291 { "files", "File descriptors", "Listing of all file descriptors",
1292 linux_xfer_osdata_fds
, -1 },
1293 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1294 linux_xfer_osdata_modules
, -1 },
1295 { "msg", "Message queues", "Listing of all message queues",
1296 linux_xfer_osdata_msg
, -1 },
1297 { "processes", "Processes", "Listing of all processes",
1298 linux_xfer_osdata_processes
, -1 },
1299 { "procgroups", "Process groups", "Listing of all process groups",
1300 linux_xfer_osdata_processgroups
, -1 },
1301 { "semaphores", "Semaphores", "Listing of all semaphores",
1302 linux_xfer_osdata_sem
, -1 },
1303 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1304 linux_xfer_osdata_shm
, -1 },
1305 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1306 linux_xfer_osdata_isockets
, -1 },
1307 { "threads", "Threads", "Listing of all threads",
1308 linux_xfer_osdata_threads
, -1 },
1309 { NULL
, NULL
, NULL
}
1312 /* Collect data about all types info os can show in BUFFER. */
1315 linux_xfer_osdata_info_os_types (struct buffer
*buffer
)
1317 buffer_grow_str (buffer
, "<osdata type=\"types\">\n");
1319 /* Start the below loop at 1, as we do not want to list ourselves. */
1320 for (int i
= 1; osdata_table
[i
].type
; ++i
)
1321 buffer_xml_printf (buffer
,
1323 "<column name=\"Type\">%s</column>"
1324 "<column name=\"Description\">%s</column>"
1325 "<column name=\"Title\">%s</column>"
1327 osdata_table
[i
].type
,
1328 osdata_table
[i
].description
,
1329 osdata_table
[i
].title
);
1331 buffer_grow_str0 (buffer
, "</osdata>\n");
1335 /* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1336 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
1339 common_getter (struct osdata_type
*osd
,
1340 gdb_byte
*readbuf
, ULONGEST offset
, ULONGEST len
)
1342 gdb_assert (readbuf
);
1346 if (osd
->len_avail
!= -1 && osd
->len_avail
!= 0)
1347 buffer_free (&osd
->buffer
);
1349 buffer_init (&osd
->buffer
);
1350 (osd
->take_snapshot
) (&osd
->buffer
);
1351 osd
->len_avail
= strlen (osd
->buffer
.buffer
);
1353 if (offset
>= osd
->len_avail
)
1355 /* Done. Get rid of the buffer. */
1356 buffer_free (&osd
->buffer
);
1360 if (len
> osd
->len_avail
- offset
)
1361 len
= osd
->len_avail
- offset
;
1362 memcpy (readbuf
, osd
->buffer
.buffer
+ offset
, len
);
1369 linux_common_xfer_osdata (const char *annex
, gdb_byte
*readbuf
,
1370 ULONGEST offset
, ULONGEST len
)
1372 if (!annex
|| *annex
== '\0')
1374 return common_getter (&osdata_table
[0],
1375 readbuf
, offset
, len
);
1381 for (i
= 0; osdata_table
[i
].type
; ++i
)
1383 if (strcmp (annex
, osdata_table
[i
].type
) == 0)
1384 return common_getter (&osdata_table
[i
],
1385 readbuf
, offset
, len
);