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
;
211 getpwuid_r (uid
, &pwd
, buf
, sizeof (buf
), &pwentry
);
215 strncpy (user
, pwentry
->pw_name
, maxlen
);
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
];
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
);
323 cores_str
= (char *) xcalloc (task_count
, sizeof ("4294967295") + 1);
325 for (i
= 0; i
< num_cores
&& task_count
> 0; ++i
)
328 char core_str
[sizeof ("4294967295")];
330 sprintf (core_str
, "%d", i
);
331 strcat (cores_str
, core_str
);
333 task_count
-= cores
[i
];
335 strcat (cores_str
, ",");
343 "<column name=\"pid\">%lld</column>"
344 "<column name=\"user\">%s</column>"
345 "<column name=\"command\">%s</column>"
346 "<column name=\"cores\">%s</column>"
350 command_line
? command_line
: "",
353 xfree (command_line
);
360 buffer_grow_str0 (buffer
, "</osdata>\n");
363 /* A simple PID/PGID pair. */
365 struct pid_pgid_entry
367 pid_pgid_entry (PID_T pid_
, PID_T pgid_
)
368 : pid (pid_
), pgid (pgid_
)
371 /* Return true if this pid is the leader of its process group. */
373 bool is_leader () const
378 bool operator< (const pid_pgid_entry
&other
) const
381 if (this->pgid
!= other
.pgid
)
382 return this->pgid
< other
.pgid
;
384 /* Process group leaders always come first... */
385 if (this->is_leader ())
387 if (!other
.is_leader ())
390 else if (other
.is_leader ())
393 /* ...else sort by PID. */
394 return this->pid
< other
.pid
;
400 /* Collect all process groups from /proc in BUFFER. */
403 linux_xfer_osdata_processgroups (struct buffer
*buffer
)
407 buffer_grow_str (buffer
, "<osdata type=\"process groups\">\n");
409 dirp
= opendir ("/proc");
412 std::vector
<pid_pgid_entry
> process_list
;
415 process_list
.reserve (512);
417 /* Build list consisting of PIDs followed by their
419 while ((dp
= readdir (dirp
)) != NULL
)
423 if (!isdigit (dp
->d_name
[0])
424 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
427 sscanf (dp
->d_name
, "%lld", &pid
);
428 pgid
= getpgid (pid
);
431 process_list
.emplace_back (pid
, pgid
);
436 /* Sort the process list. */
437 std::sort (process_list
.begin (), process_list
.end ());
439 for (const pid_pgid_entry
&entry
: process_list
)
441 PID_T pid
= entry
.pid
;
442 PID_T pgid
= entry
.pgid
;
443 char leader_command
[32];
446 command_from_pid (leader_command
, sizeof (leader_command
), pgid
);
447 command_line
= commandline_from_pid (pid
);
452 "<column name=\"pgid\">%lld</column>"
453 "<column name=\"leader command\">%s</column>"
454 "<column name=\"pid\">%lld</column>"
455 "<column name=\"command line\">%s</column>"
460 command_line
? command_line
: "");
462 xfree (command_line
);
466 buffer_grow_str0 (buffer
, "</osdata>\n");
469 /* Collect all the threads in /proc by iterating through processes and
470 then tasks within each process in BUFFER. */
473 linux_xfer_osdata_threads (struct buffer
*buffer
)
477 buffer_grow_str (buffer
, "<osdata type=\"threads\">\n");
479 dirp
= opendir ("/proc");
484 while ((dp
= readdir (dirp
)) != NULL
)
487 char procentry
[sizeof ("/proc/4294967295")];
489 if (!isdigit (dp
->d_name
[0])
490 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
493 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
495 if (stat (procentry
, &statbuf
) == 0
496 && S_ISDIR (statbuf
.st_mode
))
503 = string_printf ("/proc/%s/task", dp
->d_name
);
505 pid
= atoi (dp
->d_name
);
506 command_from_pid (command
, sizeof (command
), pid
);
508 dirp2
= opendir (pathname
.c_str ());
514 while ((dp2
= readdir (dirp2
)) != NULL
)
519 if (!isdigit (dp2
->d_name
[0])
520 || NAMELEN (dp2
) > sizeof ("4294967295") - 1)
523 tid
= atoi (dp2
->d_name
);
524 core
= linux_common_core_of_thread (ptid_t (pid
, tid
, 0));
529 "<column name=\"pid\">%lld</column>"
530 "<column name=\"command\">%s</column>"
531 "<column name=\"tid\">%lld</column>"
532 "<column name=\"core\">%d</column>"
548 buffer_grow_str0 (buffer
, "</osdata>\n");
551 /* Collect data about the cpus/cores on the system in BUFFER. */
554 linux_xfer_osdata_cpus (struct buffer
*buffer
)
558 buffer_grow_str (buffer
, "<osdata type=\"cpus\">\n");
560 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/cpuinfo", "r");
567 if (fgets (buf
, sizeof (buf
), fp
.get ()))
573 key
= strtok_r (buf
, ":", &saveptr
);
577 value
= strtok_r (NULL
, ":", &saveptr
);
581 while (key
[i
] != '\t' && key
[i
] != '\0')
587 while (value
[i
] != '\t' && value
[i
] != '\0')
592 if (strcmp (key
, "processor") == 0)
595 buffer_grow_str (buffer
, "<item>");
597 buffer_grow_str (buffer
, "</item><item>");
602 buffer_xml_printf (buffer
,
603 "<column name=\"%s\">%s</column>",
608 while (!feof (fp
.get ()));
611 buffer_grow_str (buffer
, "</item>");
614 buffer_grow_str0 (buffer
, "</osdata>\n");
617 /* Collect all the open file descriptors found in /proc and put the details
618 found about them into BUFFER. */
621 linux_xfer_osdata_fds (struct buffer
*buffer
)
625 buffer_grow_str (buffer
, "<osdata type=\"files\">\n");
627 dirp
= opendir ("/proc");
632 while ((dp
= readdir (dirp
)) != NULL
)
635 char procentry
[sizeof ("/proc/4294967295")];
637 if (!isdigit (dp
->d_name
[0])
638 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
641 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
643 if (stat (procentry
, &statbuf
) == 0
644 && S_ISDIR (statbuf
.st_mode
))
650 pid
= atoi (dp
->d_name
);
651 command_from_pid (command
, sizeof (command
), pid
);
654 = string_printf ("/proc/%s/fd", dp
->d_name
);
655 dirp2
= opendir (pathname
.c_str ());
661 while ((dp2
= readdir (dirp2
)) != NULL
)
666 if (!isdigit (dp2
->d_name
[0]))
670 = string_printf ("%s/%s", pathname
.c_str (),
672 rslt
= readlink (fdname
.c_str (), buf
,
680 "<column name=\"pid\">%s</column>"
681 "<column name=\"command\">%s</column>"
682 "<column name=\"file descriptor\">%s</column>"
683 "<column name=\"name\">%s</column>"
688 (rslt
>= 0 ? buf
: dp2
->d_name
));
699 buffer_grow_str0 (buffer
, "</osdata>\n");
702 /* Returns the socket state STATE in textual form. */
705 format_socket_state (unsigned char state
)
707 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
724 case TCP_ESTABLISHED
:
725 return "ESTABLISHED";
754 struct sockaddr_in sin
;
755 struct sockaddr_in6 sin6
;
758 /* Auxiliary function used by linux_xfer_osdata_isocket. Formats
759 information for all open internet sockets of type FAMILY on the
760 system into BUFFER. If TCP is set, only TCP sockets are processed,
761 otherwise only UDP sockets are processed. */
764 print_sockets (unsigned short family
, int tcp
, struct buffer
*buffer
)
766 const char *proc_file
;
768 if (family
== AF_INET
)
769 proc_file
= tcp
? "/proc/net/tcp" : "/proc/net/udp";
770 else if (family
== AF_INET6
)
771 proc_file
= tcp
? "/proc/net/tcp6" : "/proc/net/udp6";
775 gdb_file_up fp
= gdb_fopen_cloexec (proc_file
, "r");
782 if (fgets (buf
, sizeof (buf
), fp
.get ()))
785 unsigned int local_port
, remote_port
, state
;
786 char local_address
[NI_MAXHOST
], remote_address
[NI_MAXHOST
];
790 #error "local_address and remote_address buffers too small"
793 result
= sscanf (buf
,
794 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
795 local_address
, &local_port
,
796 remote_address
, &remote_port
,
802 union socket_addr locaddr
, remaddr
;
804 char user
[UT_NAMESIZE
];
805 char local_service
[NI_MAXSERV
], remote_service
[NI_MAXSERV
];
807 if (family
== AF_INET
)
809 sscanf (local_address
, "%X",
810 &locaddr
.sin
.sin_addr
.s_addr
);
811 sscanf (remote_address
, "%X",
812 &remaddr
.sin
.sin_addr
.s_addr
);
814 locaddr
.sin
.sin_port
= htons (local_port
);
815 remaddr
.sin
.sin_port
= htons (remote_port
);
817 addr_size
= sizeof (struct sockaddr_in
);
821 sscanf (local_address
, "%8X%8X%8X%8X",
822 locaddr
.sin6
.sin6_addr
.s6_addr32
,
823 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
824 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
825 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
826 sscanf (remote_address
, "%8X%8X%8X%8X",
827 remaddr
.sin6
.sin6_addr
.s6_addr32
,
828 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
829 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
830 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
832 locaddr
.sin6
.sin6_port
= htons (local_port
);
833 remaddr
.sin6
.sin6_port
= htons (remote_port
);
835 locaddr
.sin6
.sin6_flowinfo
= 0;
836 remaddr
.sin6
.sin6_flowinfo
= 0;
837 locaddr
.sin6
.sin6_scope_id
= 0;
838 remaddr
.sin6
.sin6_scope_id
= 0;
840 addr_size
= sizeof (struct sockaddr_in6
);
843 locaddr
.sa
.sa_family
= remaddr
.sa
.sa_family
= family
;
845 result
= getnameinfo (&locaddr
.sa
, addr_size
,
846 local_address
, sizeof (local_address
),
847 local_service
, sizeof (local_service
),
848 NI_NUMERICHOST
| NI_NUMERICSERV
849 | (tcp
? 0 : NI_DGRAM
));
853 result
= getnameinfo (&remaddr
.sa
, addr_size
,
855 sizeof (remote_address
),
857 sizeof (remote_service
),
858 NI_NUMERICHOST
| NI_NUMERICSERV
859 | (tcp
? 0 : NI_DGRAM
));
863 user_from_uid (user
, sizeof (user
), uid
);
868 "<column name=\"local address\">%s</column>"
869 "<column name=\"local port\">%s</column>"
870 "<column name=\"remote address\">%s</column>"
871 "<column name=\"remote port\">%s</column>"
872 "<column name=\"state\">%s</column>"
873 "<column name=\"user\">%s</column>"
874 "<column name=\"family\">%s</column>"
875 "<column name=\"protocol\">%s</column>"
881 format_socket_state (state
),
883 (family
== AF_INET
) ? "INET" : "INET6",
884 tcp
? "STREAM" : "DGRAM");
888 while (!feof (fp
.get ()));
892 /* Collect data about internet sockets and write it into BUFFER. */
895 linux_xfer_osdata_isockets (struct buffer
*buffer
)
897 buffer_grow_str (buffer
, "<osdata type=\"I sockets\">\n");
899 print_sockets (AF_INET
, 1, buffer
);
900 print_sockets (AF_INET
, 0, buffer
);
901 print_sockets (AF_INET6
, 1, buffer
);
902 print_sockets (AF_INET6
, 0, buffer
);
904 buffer_grow_str0 (buffer
, "</osdata>\n");
907 /* Converts the time SECONDS into textual form and copies it into a
908 buffer TIME, with at most MAXLEN characters copied. */
911 time_from_time_t (char *time
, int maxlen
, TIME_T seconds
)
917 time_t t
= (time_t) seconds
;
919 strncpy (time
, ctime (&t
), maxlen
);
920 time
[maxlen
- 1] = '\0';
924 /* Finds the group name for the group GID and copies it into GROUP.
925 At most MAXLEN characters are copied. */
928 group_from_gid (char *group
, int maxlen
, gid_t gid
)
930 struct group
*grentry
= getgrgid (gid
);
934 strncpy (group
, grentry
->gr_name
, maxlen
);
935 /* Ensure that the group name is null-terminated. */
936 group
[maxlen
- 1] = '\0';
942 /* Collect data about shared memory recorded in /proc and write it
946 linux_xfer_osdata_shm (struct buffer
*buffer
)
948 buffer_grow_str (buffer
, "<osdata type=\"shared memory\">\n");
950 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
957 if (fgets (buf
, sizeof (buf
), fp
.get ()))
963 int shmid
, size
, nattch
;
964 TIME_T atime
, dtime
, ctime
;
968 items_read
= sscanf (buf
,
969 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
970 &key
, &shmid
, &perms
, &size
,
973 &uid
, &gid
, &cuid
, &cgid
,
974 &atime
, &dtime
, &ctime
);
976 if (items_read
== 14)
978 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
979 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
980 char ccmd
[32], lcmd
[32];
981 char atime_str
[32], dtime_str
[32], ctime_str
[32];
983 user_from_uid (user
, sizeof (user
), uid
);
984 group_from_gid (group
, sizeof (group
), gid
);
985 user_from_uid (cuser
, sizeof (cuser
), cuid
);
986 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
988 command_from_pid (ccmd
, sizeof (ccmd
), cpid
);
989 command_from_pid (lcmd
, sizeof (lcmd
), lpid
);
991 time_from_time_t (atime_str
, sizeof (atime_str
), atime
);
992 time_from_time_t (dtime_str
, sizeof (dtime_str
), dtime
);
993 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
998 "<column name=\"key\">%d</column>"
999 "<column name=\"shmid\">%d</column>"
1000 "<column name=\"permissions\">%o</column>"
1001 "<column name=\"size\">%d</column>"
1002 "<column name=\"creator command\">%s</column>"
1003 "<column name=\"last op. command\">%s</column>"
1004 "<column name=\"num attached\">%d</column>"
1005 "<column name=\"user\">%s</column>"
1006 "<column name=\"group\">%s</column>"
1007 "<column name=\"creator user\">%s</column>"
1008 "<column name=\"creator group\">%s</column>"
1009 "<column name=\"last shmat() time\">%s</column>"
1010 "<column name=\"last shmdt() time\">%s</column>"
1011 "<column name=\"last shmctl() time\">%s</column>"
1030 while (!feof (fp
.get ()));
1033 buffer_grow_str0 (buffer
, "</osdata>\n");
1036 /* Collect data about semaphores recorded in /proc and write it
1040 linux_xfer_osdata_sem (struct buffer
*buffer
)
1042 buffer_grow_str (buffer
, "<osdata type=\"semaphores\">\n");
1044 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1051 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1056 unsigned int perms
, nsems
;
1058 TIME_T otime
, ctime
;
1061 items_read
= sscanf (buf
,
1062 "%d %d %o %u %d %d %d %d %lld %lld",
1063 &key
, &semid
, &perms
, &nsems
,
1064 &uid
, &gid
, &cuid
, &cgid
,
1067 if (items_read
== 10)
1069 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1070 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1071 char otime_str
[32], ctime_str
[32];
1073 user_from_uid (user
, sizeof (user
), uid
);
1074 group_from_gid (group
, sizeof (group
), gid
);
1075 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1076 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1078 time_from_time_t (otime_str
, sizeof (otime_str
), otime
);
1079 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1084 "<column name=\"key\">%d</column>"
1085 "<column name=\"semid\">%d</column>"
1086 "<column name=\"permissions\">%o</column>"
1087 "<column name=\"num semaphores\">%u</column>"
1088 "<column name=\"user\">%s</column>"
1089 "<column name=\"group\">%s</column>"
1090 "<column name=\"creator user\">%s</column>"
1091 "<column name=\"creator group\">%s</column>"
1092 "<column name=\"last semop() time\">%s</column>"
1093 "<column name=\"last semctl() time\">%s</column>"
1108 while (!feof (fp
.get ()));
1111 buffer_grow_str0 (buffer
, "</osdata>\n");
1114 /* Collect data about message queues recorded in /proc and write it
1118 linux_xfer_osdata_msg (struct buffer
*buffer
)
1120 buffer_grow_str (buffer
, "<osdata type=\"message queues\">\n");
1122 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1129 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1135 unsigned int perms
, cbytes
, qnum
;
1137 TIME_T stime
, rtime
, ctime
;
1140 items_read
= sscanf (buf
,
1141 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1142 &key
, &msqid
, &perms
, &cbytes
, &qnum
,
1143 &lspid
, &lrpid
, &uid
, &gid
, &cuid
, &cgid
,
1144 &stime
, &rtime
, &ctime
);
1146 if (items_read
== 14)
1148 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1149 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1150 char lscmd
[32], lrcmd
[32];
1151 char stime_str
[32], rtime_str
[32], ctime_str
[32];
1153 user_from_uid (user
, sizeof (user
), uid
);
1154 group_from_gid (group
, sizeof (group
), gid
);
1155 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1156 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1158 command_from_pid (lscmd
, sizeof (lscmd
), lspid
);
1159 command_from_pid (lrcmd
, sizeof (lrcmd
), lrpid
);
1161 time_from_time_t (stime_str
, sizeof (stime_str
), stime
);
1162 time_from_time_t (rtime_str
, sizeof (rtime_str
), rtime
);
1163 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1168 "<column name=\"key\">%d</column>"
1169 "<column name=\"msqid\">%d</column>"
1170 "<column name=\"permissions\">%o</column>"
1171 "<column name=\"num used bytes\">%u</column>"
1172 "<column name=\"num messages\">%u</column>"
1173 "<column name=\"last msgsnd() command\">%s</column>"
1174 "<column name=\"last msgrcv() command\">%s</column>"
1175 "<column name=\"user\">%s</column>"
1176 "<column name=\"group\">%s</column>"
1177 "<column name=\"creator user\">%s</column>"
1178 "<column name=\"creator group\">%s</column>"
1179 "<column name=\"last msgsnd() time\">%s</column>"
1180 "<column name=\"last msgrcv() time\">%s</column>"
1181 "<column name=\"last msgctl() time\">%s</column>"
1200 while (!feof (fp
.get ()));
1203 buffer_grow_str0 (buffer
, "</osdata>\n");
1206 /* Collect data about loaded kernel modules and write it into
1210 linux_xfer_osdata_modules (struct buffer
*buffer
)
1212 buffer_grow_str (buffer
, "<osdata type=\"modules\">\n");
1214 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/modules", "r");
1221 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1223 char *name
, *dependencies
, *status
, *tmp
, *saveptr
;
1225 unsigned long long address
;
1228 name
= strtok_r (buf
, " ", &saveptr
);
1232 tmp
= strtok_r (NULL
, " ", &saveptr
);
1235 if (sscanf (tmp
, "%u", &size
) != 1)
1238 tmp
= strtok_r (NULL
, " ", &saveptr
);
1241 if (sscanf (tmp
, "%d", &uses
) != 1)
1244 dependencies
= strtok_r (NULL
, " ", &saveptr
);
1245 if (dependencies
== NULL
)
1248 status
= strtok_r (NULL
, " ", &saveptr
);
1252 tmp
= strtok_r (NULL
, "\n", &saveptr
);
1255 if (sscanf (tmp
, "%llx", &address
) != 1)
1258 buffer_xml_printf (buffer
,
1260 "<column name=\"name\">%s</column>"
1261 "<column name=\"size\">%u</column>"
1262 "<column name=\"num uses\">%d</column>"
1263 "<column name=\"dependencies\">%s</column>"
1264 "<column name=\"status\">%s</column>"
1265 "<column name=\"address\">%llx</column>"
1275 while (!feof (fp
.get ()));
1278 buffer_grow_str0 (buffer
, "</osdata>\n");
1281 static void linux_xfer_osdata_info_os_types (struct buffer
*buffer
);
1283 struct osdata_type
{
1286 const char *description
;
1287 void (*take_snapshot
) (struct buffer
*buffer
);
1289 struct buffer buffer
;
1290 } osdata_table
[] = {
1291 { "types", "Types", "Listing of info os types you can list",
1292 linux_xfer_osdata_info_os_types
, -1 },
1293 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1294 linux_xfer_osdata_cpus
, -1 },
1295 { "files", "File descriptors", "Listing of all file descriptors",
1296 linux_xfer_osdata_fds
, -1 },
1297 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1298 linux_xfer_osdata_modules
, -1 },
1299 { "msg", "Message queues", "Listing of all message queues",
1300 linux_xfer_osdata_msg
, -1 },
1301 { "processes", "Processes", "Listing of all processes",
1302 linux_xfer_osdata_processes
, -1 },
1303 { "procgroups", "Process groups", "Listing of all process groups",
1304 linux_xfer_osdata_processgroups
, -1 },
1305 { "semaphores", "Semaphores", "Listing of all semaphores",
1306 linux_xfer_osdata_sem
, -1 },
1307 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1308 linux_xfer_osdata_shm
, -1 },
1309 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1310 linux_xfer_osdata_isockets
, -1 },
1311 { "threads", "Threads", "Listing of all threads",
1312 linux_xfer_osdata_threads
, -1 },
1313 { NULL
, NULL
, NULL
}
1316 /* Collect data about all types info os can show in BUFFER. */
1319 linux_xfer_osdata_info_os_types (struct buffer
*buffer
)
1321 buffer_grow_str (buffer
, "<osdata type=\"types\">\n");
1323 /* Start the below loop at 1, as we do not want to list ourselves. */
1324 for (int i
= 1; osdata_table
[i
].type
; ++i
)
1325 buffer_xml_printf (buffer
,
1327 "<column name=\"Type\">%s</column>"
1328 "<column name=\"Description\">%s</column>"
1329 "<column name=\"Title\">%s</column>"
1331 osdata_table
[i
].type
,
1332 osdata_table
[i
].description
,
1333 osdata_table
[i
].title
);
1335 buffer_grow_str0 (buffer
, "</osdata>\n");
1339 /* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1340 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
1343 common_getter (struct osdata_type
*osd
,
1344 gdb_byte
*readbuf
, ULONGEST offset
, ULONGEST len
)
1346 gdb_assert (readbuf
);
1350 if (osd
->len_avail
!= -1 && osd
->len_avail
!= 0)
1351 buffer_free (&osd
->buffer
);
1353 buffer_init (&osd
->buffer
);
1354 (osd
->take_snapshot
) (&osd
->buffer
);
1355 osd
->len_avail
= strlen (osd
->buffer
.buffer
);
1357 if (offset
>= osd
->len_avail
)
1359 /* Done. Get rid of the buffer. */
1360 buffer_free (&osd
->buffer
);
1364 if (len
> osd
->len_avail
- offset
)
1365 len
= osd
->len_avail
- offset
;
1366 memcpy (readbuf
, osd
->buffer
.buffer
+ offset
, len
);
1373 linux_common_xfer_osdata (const char *annex
, gdb_byte
*readbuf
,
1374 ULONGEST offset
, ULONGEST len
)
1376 if (!annex
|| *annex
== '\0')
1378 return common_getter (&osdata_table
[0],
1379 readbuf
, offset
, len
);
1385 for (i
= 0; osdata_table
[i
].type
; ++i
)
1387 if (strcmp (annex
, osdata_table
[i
].type
) == 0)
1388 return common_getter (&osdata_table
[i
],
1389 readbuf
, offset
, len
);