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 "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
= 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 ()))
570 key
= strtok_r (buf
, ":", &saveptr
);
574 value
= strtok_r (NULL
, ":", &saveptr
);
578 while (key
[i
] != '\t' && key
[i
] != '\0')
584 while (value
[i
] != '\t' && value
[i
] != '\0')
589 if (strcmp (key
, "processor") == 0)
592 buffer_grow_str (buffer
, "<item>");
594 buffer_grow_str (buffer
, "</item><item>");
599 buffer_xml_printf (buffer
,
600 "<column name=\"%s\">%s</column>",
605 while (!feof (fp
.get ()));
608 buffer_grow_str (buffer
, "</item>");
611 buffer_grow_str0 (buffer
, "</osdata>\n");
614 /* Collect all the open file descriptors found in /proc and put the details
615 found about them into BUFFER. */
618 linux_xfer_osdata_fds (struct buffer
*buffer
)
622 buffer_grow_str (buffer
, "<osdata type=\"files\">\n");
624 dirp
= opendir ("/proc");
629 while ((dp
= readdir (dirp
)) != NULL
)
632 char procentry
[sizeof ("/proc/4294967295")];
634 if (!isdigit (dp
->d_name
[0])
635 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
638 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
640 if (stat (procentry
, &statbuf
) == 0
641 && S_ISDIR (statbuf
.st_mode
))
647 pid
= atoi (dp
->d_name
);
648 command_from_pid (command
, sizeof (command
), pid
);
651 = string_printf ("/proc/%s/fd", dp
->d_name
);
652 dirp2
= opendir (pathname
.c_str ());
658 while ((dp2
= readdir (dirp2
)) != NULL
)
663 if (!isdigit (dp2
->d_name
[0]))
667 = string_printf ("%s/%s", pathname
.c_str (),
669 rslt
= readlink (fdname
.c_str (), buf
,
677 "<column name=\"pid\">%s</column>"
678 "<column name=\"command\">%s</column>"
679 "<column name=\"file descriptor\">%s</column>"
680 "<column name=\"name\">%s</column>"
685 (rslt
>= 0 ? buf
: dp2
->d_name
));
696 buffer_grow_str0 (buffer
, "</osdata>\n");
699 /* Returns the socket state STATE in textual form. */
702 format_socket_state (unsigned char state
)
704 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
721 case TCP_ESTABLISHED
:
722 return "ESTABLISHED";
751 struct sockaddr_in sin
;
752 struct sockaddr_in6 sin6
;
755 /* Auxiliary function used by linux_xfer_osdata_isocket. Formats
756 information for all open internet sockets of type FAMILY on the
757 system into BUFFER. If TCP is set, only TCP sockets are processed,
758 otherwise only UDP sockets are processed. */
761 print_sockets (unsigned short family
, int tcp
, struct buffer
*buffer
)
763 const char *proc_file
;
765 if (family
== AF_INET
)
766 proc_file
= tcp
? "/proc/net/tcp" : "/proc/net/udp";
767 else if (family
== AF_INET6
)
768 proc_file
= tcp
? "/proc/net/tcp6" : "/proc/net/udp6";
772 gdb_file_up fp
= gdb_fopen_cloexec (proc_file
, "r");
779 if (fgets (buf
, sizeof (buf
), fp
.get ()))
782 unsigned int local_port
, remote_port
, state
;
783 char local_address
[NI_MAXHOST
], remote_address
[NI_MAXHOST
];
787 #error "local_address and remote_address buffers too small"
790 result
= sscanf (buf
,
791 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
792 local_address
, &local_port
,
793 remote_address
, &remote_port
,
799 union socket_addr locaddr
, remaddr
;
801 char user
[UT_NAMESIZE
];
802 char local_service
[NI_MAXSERV
], remote_service
[NI_MAXSERV
];
804 if (family
== AF_INET
)
806 sscanf (local_address
, "%X",
807 &locaddr
.sin
.sin_addr
.s_addr
);
808 sscanf (remote_address
, "%X",
809 &remaddr
.sin
.sin_addr
.s_addr
);
811 locaddr
.sin
.sin_port
= htons (local_port
);
812 remaddr
.sin
.sin_port
= htons (remote_port
);
814 addr_size
= sizeof (struct sockaddr_in
);
818 sscanf (local_address
, "%8X%8X%8X%8X",
819 locaddr
.sin6
.sin6_addr
.s6_addr32
,
820 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
821 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
822 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
823 sscanf (remote_address
, "%8X%8X%8X%8X",
824 remaddr
.sin6
.sin6_addr
.s6_addr32
,
825 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
826 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
827 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
829 locaddr
.sin6
.sin6_port
= htons (local_port
);
830 remaddr
.sin6
.sin6_port
= htons (remote_port
);
832 locaddr
.sin6
.sin6_flowinfo
= 0;
833 remaddr
.sin6
.sin6_flowinfo
= 0;
834 locaddr
.sin6
.sin6_scope_id
= 0;
835 remaddr
.sin6
.sin6_scope_id
= 0;
837 addr_size
= sizeof (struct sockaddr_in6
);
840 locaddr
.sa
.sa_family
= remaddr
.sa
.sa_family
= family
;
842 result
= getnameinfo (&locaddr
.sa
, addr_size
,
843 local_address
, sizeof (local_address
),
844 local_service
, sizeof (local_service
),
845 NI_NUMERICHOST
| NI_NUMERICSERV
846 | (tcp
? 0 : NI_DGRAM
));
850 result
= getnameinfo (&remaddr
.sa
, addr_size
,
852 sizeof (remote_address
),
854 sizeof (remote_service
),
855 NI_NUMERICHOST
| NI_NUMERICSERV
856 | (tcp
? 0 : NI_DGRAM
));
860 user_from_uid (user
, sizeof (user
), uid
);
865 "<column name=\"local address\">%s</column>"
866 "<column name=\"local port\">%s</column>"
867 "<column name=\"remote address\">%s</column>"
868 "<column name=\"remote port\">%s</column>"
869 "<column name=\"state\">%s</column>"
870 "<column name=\"user\">%s</column>"
871 "<column name=\"family\">%s</column>"
872 "<column name=\"protocol\">%s</column>"
878 format_socket_state (state
),
880 (family
== AF_INET
) ? "INET" : "INET6",
881 tcp
? "STREAM" : "DGRAM");
885 while (!feof (fp
.get ()));
889 /* Collect data about internet sockets and write it into BUFFER. */
892 linux_xfer_osdata_isockets (struct buffer
*buffer
)
894 buffer_grow_str (buffer
, "<osdata type=\"I sockets\">\n");
896 print_sockets (AF_INET
, 1, buffer
);
897 print_sockets (AF_INET
, 0, buffer
);
898 print_sockets (AF_INET6
, 1, buffer
);
899 print_sockets (AF_INET6
, 0, buffer
);
901 buffer_grow_str0 (buffer
, "</osdata>\n");
904 /* Converts the time SECONDS into textual form and copies it into a
905 buffer TIME, with at most MAXLEN characters copied. */
908 time_from_time_t (char *time
, int maxlen
, TIME_T seconds
)
914 time_t t
= (time_t) seconds
;
916 strncpy (time
, ctime (&t
), maxlen
);
917 time
[maxlen
- 1] = '\0';
921 /* Finds the group name for the group GID and copies it into GROUP.
922 At most MAXLEN characters are copied. */
925 group_from_gid (char *group
, int maxlen
, gid_t gid
)
927 struct group
*grentry
= getgrgid (gid
);
931 strncpy (group
, grentry
->gr_name
, maxlen
);
932 /* Ensure that the group name is null-terminated. */
933 group
[maxlen
- 1] = '\0';
939 /* Collect data about shared memory recorded in /proc and write it
943 linux_xfer_osdata_shm (struct buffer
*buffer
)
945 buffer_grow_str (buffer
, "<osdata type=\"shared memory\">\n");
947 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
954 if (fgets (buf
, sizeof (buf
), fp
.get ()))
960 int shmid
, size
, nattch
;
961 TIME_T atime
, dtime
, ctime
;
965 items_read
= sscanf (buf
,
966 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
967 &key
, &shmid
, &perms
, &size
,
970 &uid
, &gid
, &cuid
, &cgid
,
971 &atime
, &dtime
, &ctime
);
973 if (items_read
== 14)
975 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
976 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
977 char ccmd
[32], lcmd
[32];
978 char atime_str
[32], dtime_str
[32], ctime_str
[32];
980 user_from_uid (user
, sizeof (user
), uid
);
981 group_from_gid (group
, sizeof (group
), gid
);
982 user_from_uid (cuser
, sizeof (cuser
), cuid
);
983 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
985 command_from_pid (ccmd
, sizeof (ccmd
), cpid
);
986 command_from_pid (lcmd
, sizeof (lcmd
), lpid
);
988 time_from_time_t (atime_str
, sizeof (atime_str
), atime
);
989 time_from_time_t (dtime_str
, sizeof (dtime_str
), dtime
);
990 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
995 "<column name=\"key\">%d</column>"
996 "<column name=\"shmid\">%d</column>"
997 "<column name=\"permissions\">%o</column>"
998 "<column name=\"size\">%d</column>"
999 "<column name=\"creator command\">%s</column>"
1000 "<column name=\"last op. command\">%s</column>"
1001 "<column name=\"num attached\">%d</column>"
1002 "<column name=\"user\">%s</column>"
1003 "<column name=\"group\">%s</column>"
1004 "<column name=\"creator user\">%s</column>"
1005 "<column name=\"creator group\">%s</column>"
1006 "<column name=\"last shmat() time\">%s</column>"
1007 "<column name=\"last shmdt() time\">%s</column>"
1008 "<column name=\"last shmctl() time\">%s</column>"
1027 while (!feof (fp
.get ()));
1030 buffer_grow_str0 (buffer
, "</osdata>\n");
1033 /* Collect data about semaphores recorded in /proc and write it
1037 linux_xfer_osdata_sem (struct buffer
*buffer
)
1039 buffer_grow_str (buffer
, "<osdata type=\"semaphores\">\n");
1041 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1048 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1053 unsigned int perms
, nsems
;
1055 TIME_T otime
, ctime
;
1058 items_read
= sscanf (buf
,
1059 "%d %d %o %u %d %d %d %d %lld %lld",
1060 &key
, &semid
, &perms
, &nsems
,
1061 &uid
, &gid
, &cuid
, &cgid
,
1064 if (items_read
== 10)
1066 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1067 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1068 char otime_str
[32], ctime_str
[32];
1070 user_from_uid (user
, sizeof (user
), uid
);
1071 group_from_gid (group
, sizeof (group
), gid
);
1072 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1073 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1075 time_from_time_t (otime_str
, sizeof (otime_str
), otime
);
1076 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1081 "<column name=\"key\">%d</column>"
1082 "<column name=\"semid\">%d</column>"
1083 "<column name=\"permissions\">%o</column>"
1084 "<column name=\"num semaphores\">%u</column>"
1085 "<column name=\"user\">%s</column>"
1086 "<column name=\"group\">%s</column>"
1087 "<column name=\"creator user\">%s</column>"
1088 "<column name=\"creator group\">%s</column>"
1089 "<column name=\"last semop() time\">%s</column>"
1090 "<column name=\"last semctl() time\">%s</column>"
1105 while (!feof (fp
.get ()));
1108 buffer_grow_str0 (buffer
, "</osdata>\n");
1111 /* Collect data about message queues recorded in /proc and write it
1115 linux_xfer_osdata_msg (struct buffer
*buffer
)
1117 buffer_grow_str (buffer
, "<osdata type=\"message queues\">\n");
1119 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1126 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1132 unsigned int perms
, cbytes
, qnum
;
1134 TIME_T stime
, rtime
, ctime
;
1137 items_read
= sscanf (buf
,
1138 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1139 &key
, &msqid
, &perms
, &cbytes
, &qnum
,
1140 &lspid
, &lrpid
, &uid
, &gid
, &cuid
, &cgid
,
1141 &stime
, &rtime
, &ctime
);
1143 if (items_read
== 14)
1145 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1146 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1147 char lscmd
[32], lrcmd
[32];
1148 char stime_str
[32], rtime_str
[32], ctime_str
[32];
1150 user_from_uid (user
, sizeof (user
), uid
);
1151 group_from_gid (group
, sizeof (group
), gid
);
1152 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1153 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1155 command_from_pid (lscmd
, sizeof (lscmd
), lspid
);
1156 command_from_pid (lrcmd
, sizeof (lrcmd
), lrpid
);
1158 time_from_time_t (stime_str
, sizeof (stime_str
), stime
);
1159 time_from_time_t (rtime_str
, sizeof (rtime_str
), rtime
);
1160 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1165 "<column name=\"key\">%d</column>"
1166 "<column name=\"msqid\">%d</column>"
1167 "<column name=\"permissions\">%o</column>"
1168 "<column name=\"num used bytes\">%u</column>"
1169 "<column name=\"num messages\">%u</column>"
1170 "<column name=\"last msgsnd() command\">%s</column>"
1171 "<column name=\"last msgrcv() command\">%s</column>"
1172 "<column name=\"user\">%s</column>"
1173 "<column name=\"group\">%s</column>"
1174 "<column name=\"creator user\">%s</column>"
1175 "<column name=\"creator group\">%s</column>"
1176 "<column name=\"last msgsnd() time\">%s</column>"
1177 "<column name=\"last msgrcv() time\">%s</column>"
1178 "<column name=\"last msgctl() time\">%s</column>"
1197 while (!feof (fp
.get ()));
1200 buffer_grow_str0 (buffer
, "</osdata>\n");
1203 /* Collect data about loaded kernel modules and write it into
1207 linux_xfer_osdata_modules (struct buffer
*buffer
)
1209 buffer_grow_str (buffer
, "<osdata type=\"modules\">\n");
1211 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/modules", "r");
1218 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1220 char *name
, *dependencies
, *status
, *tmp
, *saveptr
;
1222 unsigned long long address
;
1225 name
= strtok_r (buf
, " ", &saveptr
);
1229 tmp
= strtok_r (NULL
, " ", &saveptr
);
1232 if (sscanf (tmp
, "%u", &size
) != 1)
1235 tmp
= strtok_r (NULL
, " ", &saveptr
);
1238 if (sscanf (tmp
, "%d", &uses
) != 1)
1241 dependencies
= strtok_r (NULL
, " ", &saveptr
);
1242 if (dependencies
== NULL
)
1245 status
= strtok_r (NULL
, " ", &saveptr
);
1249 tmp
= strtok_r (NULL
, "\n", &saveptr
);
1252 if (sscanf (tmp
, "%llx", &address
) != 1)
1255 buffer_xml_printf (buffer
,
1257 "<column name=\"name\">%s</column>"
1258 "<column name=\"size\">%u</column>"
1259 "<column name=\"num uses\">%d</column>"
1260 "<column name=\"dependencies\">%s</column>"
1261 "<column name=\"status\">%s</column>"
1262 "<column name=\"address\">%llx</column>"
1272 while (!feof (fp
.get ()));
1275 buffer_grow_str0 (buffer
, "</osdata>\n");
1278 static void linux_xfer_osdata_info_os_types (struct buffer
*buffer
);
1280 struct osdata_type
{
1283 const char *description
;
1284 void (*take_snapshot
) (struct buffer
*buffer
);
1286 struct buffer buffer
;
1287 } osdata_table
[] = {
1288 { "types", "Types", "Listing of info os types you can list",
1289 linux_xfer_osdata_info_os_types
, -1 },
1290 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1291 linux_xfer_osdata_cpus
, -1 },
1292 { "files", "File descriptors", "Listing of all file descriptors",
1293 linux_xfer_osdata_fds
, -1 },
1294 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1295 linux_xfer_osdata_modules
, -1 },
1296 { "msg", "Message queues", "Listing of all message queues",
1297 linux_xfer_osdata_msg
, -1 },
1298 { "processes", "Processes", "Listing of all processes",
1299 linux_xfer_osdata_processes
, -1 },
1300 { "procgroups", "Process groups", "Listing of all process groups",
1301 linux_xfer_osdata_processgroups
, -1 },
1302 { "semaphores", "Semaphores", "Listing of all semaphores",
1303 linux_xfer_osdata_sem
, -1 },
1304 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1305 linux_xfer_osdata_shm
, -1 },
1306 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1307 linux_xfer_osdata_isockets
, -1 },
1308 { "threads", "Threads", "Listing of all threads",
1309 linux_xfer_osdata_threads
, -1 },
1310 { NULL
, NULL
, NULL
}
1313 /* Collect data about all types info os can show in BUFFER. */
1316 linux_xfer_osdata_info_os_types (struct buffer
*buffer
)
1318 buffer_grow_str (buffer
, "<osdata type=\"types\">\n");
1320 /* Start the below loop at 1, as we do not want to list ourselves. */
1321 for (int i
= 1; osdata_table
[i
].type
; ++i
)
1322 buffer_xml_printf (buffer
,
1324 "<column name=\"Type\">%s</column>"
1325 "<column name=\"Description\">%s</column>"
1326 "<column name=\"Title\">%s</column>"
1328 osdata_table
[i
].type
,
1329 osdata_table
[i
].description
,
1330 osdata_table
[i
].title
);
1332 buffer_grow_str0 (buffer
, "</osdata>\n");
1336 /* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1337 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
1340 common_getter (struct osdata_type
*osd
,
1341 gdb_byte
*readbuf
, ULONGEST offset
, ULONGEST len
)
1343 gdb_assert (readbuf
);
1347 if (osd
->len_avail
!= -1 && osd
->len_avail
!= 0)
1348 buffer_free (&osd
->buffer
);
1350 buffer_init (&osd
->buffer
);
1351 (osd
->take_snapshot
) (&osd
->buffer
);
1352 osd
->len_avail
= strlen (osd
->buffer
.buffer
);
1354 if (offset
>= osd
->len_avail
)
1356 /* Done. Get rid of the buffer. */
1357 buffer_free (&osd
->buffer
);
1361 if (len
> osd
->len_avail
- offset
)
1362 len
= osd
->len_avail
- offset
;
1363 memcpy (readbuf
, osd
->buffer
.buffer
+ offset
, len
);
1370 linux_common_xfer_osdata (const char *annex
, gdb_byte
*readbuf
,
1371 ULONGEST offset
, ULONGEST len
)
1373 if (!annex
|| *annex
== '\0')
1375 return common_getter (&osdata_table
[0],
1376 readbuf
, offset
, len
);
1382 for (i
= 0; osdata_table
[i
].type
; ++i
)
1384 if (strcmp (annex
, osdata_table
[i
].type
) == 0)
1385 return common_getter (&osdata_table
[i
],
1386 readbuf
, offset
, len
);