1 /* Linux-specific functions to retrieve OS data.
3 Copyright (C) 2009-2018 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-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 "xml-utils.h"
39 #include "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_get_lwp (ptid
));
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 char *stat_path
= xstrprintf ("/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. */
149 /* Returns the command-line of the process with the given PID. The
150 returned string needs to be freed using xfree after use. */
153 commandline_from_pid (PID_T pid
)
155 char *pathname
= xstrprintf ("/proc/%lld/cmdline", pid
);
156 char *commandline
= NULL
;
157 gdb_file_up f
= gdb_fopen_cloexec (pathname
, "r");
163 while (!feof (f
.get ()))
166 size_t read_bytes
= fread (buf
, 1, sizeof (buf
), f
.get ());
170 commandline
= (char *) xrealloc (commandline
, len
+ read_bytes
+ 1);
171 memcpy (commandline
+ len
, buf
, read_bytes
);
180 /* Replace null characters with spaces. */
181 for (i
= 0; i
< len
; ++i
)
182 if (commandline
[i
] == '\0')
183 commandline
[i
] = ' ';
185 commandline
[len
] = '\0';
189 /* Return the command in square brackets if the command-line
191 commandline
= (char *) xmalloc (32);
192 commandline
[0] = '[';
193 command_from_pid (commandline
+ 1, 31, pid
);
195 len
= strlen (commandline
);
197 strcat (commandline
, "]");
206 /* Finds the user name for the user UID and copies it into USER. At
207 most MAXLEN characters are copied. */
210 user_from_uid (char *user
, int maxlen
, uid_t uid
)
212 struct passwd
*pwentry
= getpwuid (uid
);
216 strncpy (user
, pwentry
->pw_name
, maxlen
);
217 /* Ensure that the user name is null-terminated. */
218 user
[maxlen
- 1] = '\0';
224 /* Finds the owner of process PID and returns the user id in OWNER.
225 Returns 0 if the owner was found, -1 otherwise. */
228 get_process_owner (uid_t
*owner
, PID_T pid
)
231 char procentry
[sizeof ("/proc/") + MAX_PID_T_STRLEN
];
233 sprintf (procentry
, "/proc/%lld", pid
);
235 if (stat (procentry
, &statbuf
) == 0 && S_ISDIR (statbuf
.st_mode
))
237 *owner
= statbuf
.st_uid
;
244 /* Find the CPU cores used by process PID and return them in CORES.
245 CORES points to an array of NUM_CORES elements. */
248 get_cores_used_by_process (PID_T pid
, int *cores
, const int num_cores
)
250 char taskdir
[sizeof ("/proc/") + MAX_PID_T_STRLEN
+ sizeof ("/task") - 1];
255 sprintf (taskdir
, "/proc/%lld/task", pid
);
256 dir
= opendir (taskdir
);
259 while ((dp
= readdir (dir
)) != NULL
)
264 if (!isdigit (dp
->d_name
[0])
265 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
268 sscanf (dp
->d_name
, "%lld", &tid
);
269 core
= linux_common_core_of_thread (ptid_t ((pid_t
) pid
,
272 if (core
>= 0 && core
< num_cores
)
286 linux_xfer_osdata_processes (gdb_byte
*readbuf
,
287 ULONGEST offset
, ULONGEST len
)
289 /* We make the process list snapshot when the object starts to be read. */
290 static const char *buf
;
291 static LONGEST len_avail
= -1;
292 static struct buffer buffer
;
298 if (len_avail
!= -1 && len_avail
!= 0)
299 buffer_free (&buffer
);
302 buffer_init (&buffer
);
303 buffer_grow_str (&buffer
, "<osdata type=\"processes\">\n");
305 dirp
= opendir ("/proc");
308 const int num_cores
= sysconf (_SC_NPROCESSORS_ONLN
);
311 while ((dp
= readdir (dirp
)) != NULL
)
315 char user
[UT_NAMESIZE
];
322 if (!isdigit (dp
->d_name
[0])
323 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
326 sscanf (dp
->d_name
, "%lld", &pid
);
327 command_line
= commandline_from_pid (pid
);
329 if (get_process_owner (&owner
, pid
) == 0)
330 user_from_uid (user
, sizeof (user
), owner
);
334 /* Find CPU cores used by the process. */
335 cores
= XCNEWVEC (int, num_cores
);
336 task_count
= get_cores_used_by_process (pid
, cores
, num_cores
);
337 cores_str
= (char *) xcalloc (task_count
, sizeof ("4294967295") + 1);
339 for (i
= 0; i
< num_cores
&& task_count
> 0; ++i
)
342 char core_str
[sizeof ("4294967295")];
344 sprintf (core_str
, "%d", i
);
345 strcat (cores_str
, core_str
);
347 task_count
-= cores
[i
];
349 strcat (cores_str
, ",");
357 "<column name=\"pid\">%lld</column>"
358 "<column name=\"user\">%s</column>"
359 "<column name=\"command\">%s</column>"
360 "<column name=\"cores\">%s</column>"
364 command_line
? command_line
: "",
367 xfree (command_line
);
374 buffer_grow_str0 (&buffer
, "</osdata>\n");
375 buf
= buffer_finish (&buffer
);
376 len_avail
= strlen (buf
);
379 if (offset
>= len_avail
)
381 /* Done. Get rid of the buffer. */
382 buffer_free (&buffer
);
388 if (len
> len_avail
- offset
)
389 len
= len_avail
- offset
;
390 memcpy (readbuf
, buf
+ offset
, len
);
395 /* A simple PID/PGID pair. */
397 struct pid_pgid_entry
399 pid_pgid_entry (PID_T pid_
, PID_T pgid_
)
400 : pid (pid_
), pgid (pgid_
)
403 /* Return true if this pid is the leader of its process group. */
405 bool is_leader () const
410 bool operator< (const pid_pgid_entry
&other
) const
413 if (this->pgid
!= other
.pgid
)
414 return this->pgid
< other
.pgid
;
416 /* Process group leaders always come first... */
417 if (this->is_leader ())
420 if (other
.is_leader ())
423 /* ...else sort by PID. */
424 return this->pid
< other
.pid
;
430 /* Collect all process groups from /proc. */
433 linux_xfer_osdata_processgroups (gdb_byte
*readbuf
,
434 ULONGEST offset
, ULONGEST len
)
436 /* We make the process list snapshot when the object starts to be read. */
437 static const char *buf
;
438 static LONGEST len_avail
= -1;
439 static struct buffer buffer
;
445 if (len_avail
!= -1 && len_avail
!= 0)
446 buffer_free (&buffer
);
449 buffer_init (&buffer
);
450 buffer_grow_str (&buffer
, "<osdata type=\"process groups\">\n");
452 dirp
= opendir ("/proc");
455 std::vector
<pid_pgid_entry
> process_list
;
458 process_list
.reserve (512);
460 /* Build list consisting of PIDs followed by their
462 while ((dp
= readdir (dirp
)) != NULL
)
466 if (!isdigit (dp
->d_name
[0])
467 || NAMELEN (dp
) > MAX_PID_T_STRLEN
)
470 sscanf (dp
->d_name
, "%lld", &pid
);
471 pgid
= getpgid (pid
);
474 process_list
.emplace_back (pid
, pgid
);
479 /* Sort the process list. */
480 std::sort (process_list
.begin (), process_list
.end ());
482 for (const pid_pgid_entry
&entry
: process_list
)
484 PID_T pid
= entry
.pid
;
485 PID_T pgid
= entry
.pgid
;
486 char leader_command
[32];
489 command_from_pid (leader_command
, sizeof (leader_command
), pgid
);
490 command_line
= commandline_from_pid (pid
);
495 "<column name=\"pgid\">%lld</column>"
496 "<column name=\"leader command\">%s</column>"
497 "<column name=\"pid\">%lld</column>"
498 "<column name=\"command line\">%s</column>"
503 command_line
? command_line
: "");
505 xfree (command_line
);
509 buffer_grow_str0 (&buffer
, "</osdata>\n");
510 buf
= buffer_finish (&buffer
);
511 len_avail
= strlen (buf
);
514 if (offset
>= len_avail
)
516 /* Done. Get rid of the buffer. */
517 buffer_free (&buffer
);
523 if (len
> len_avail
- offset
)
524 len
= len_avail
- offset
;
525 memcpy (readbuf
, buf
+ offset
, len
);
530 /* Collect all the threads in /proc by iterating through processes and
531 then tasks within each process. */
534 linux_xfer_osdata_threads (gdb_byte
*readbuf
,
535 ULONGEST offset
, ULONGEST len
)
537 /* We make the process list snapshot when the object starts to be read. */
538 static const char *buf
;
539 static LONGEST len_avail
= -1;
540 static struct buffer buffer
;
546 if (len_avail
!= -1 && len_avail
!= 0)
547 buffer_free (&buffer
);
550 buffer_init (&buffer
);
551 buffer_grow_str (&buffer
, "<osdata type=\"threads\">\n");
553 dirp
= opendir ("/proc");
558 while ((dp
= readdir (dirp
)) != NULL
)
561 char procentry
[sizeof ("/proc/4294967295")];
563 if (!isdigit (dp
->d_name
[0])
564 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
567 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
569 if (stat (procentry
, &statbuf
) == 0
570 && S_ISDIR (statbuf
.st_mode
))
577 pathname
= xstrprintf ("/proc/%s/task", dp
->d_name
);
579 pid
= atoi (dp
->d_name
);
580 command_from_pid (command
, sizeof (command
), pid
);
582 dirp2
= opendir (pathname
);
588 while ((dp2
= readdir (dirp2
)) != NULL
)
593 if (!isdigit (dp2
->d_name
[0])
594 || NAMELEN (dp2
) > sizeof ("4294967295") - 1)
597 tid
= atoi (dp2
->d_name
);
598 core
= linux_common_core_of_thread (ptid_t (pid
, tid
, 0));
603 "<column name=\"pid\">%lld</column>"
604 "<column name=\"command\">%s</column>"
605 "<column name=\"tid\">%lld</column>"
606 "<column name=\"core\">%d</column>"
624 buffer_grow_str0 (&buffer
, "</osdata>\n");
625 buf
= buffer_finish (&buffer
);
626 len_avail
= strlen (buf
);
629 if (offset
>= len_avail
)
631 /* Done. Get rid of the buffer. */
632 buffer_free (&buffer
);
638 if (len
> len_avail
- offset
)
639 len
= len_avail
- offset
;
640 memcpy (readbuf
, buf
+ offset
, len
);
645 /* Collect data about the cpus/cores on the system */
648 linux_xfer_osdata_cpus (gdb_byte
*readbuf
,
649 ULONGEST offset
, ULONGEST len
)
651 static const char *buf
;
652 static LONGEST len_avail
= -1;
653 static struct buffer buffer
;
659 if (len_avail
!= -1 && len_avail
!= 0)
660 buffer_free (&buffer
);
663 buffer_init (&buffer
);
664 buffer_grow_str (&buffer
, "<osdata type=\"cpus\">\n");
666 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/cpuinfo", "r");
673 if (fgets (buf
, sizeof (buf
), fp
.get ()))
678 key
= strtok (buf
, ":");
682 value
= strtok (NULL
, ":");
686 while (key
[i
] != '\t' && key
[i
] != '\0')
692 while (value
[i
] != '\t' && value
[i
] != '\0')
697 if (strcmp (key
, "processor") == 0)
700 buffer_grow_str (&buffer
, "<item>");
702 buffer_grow_str (&buffer
, "</item><item>");
707 buffer_xml_printf (&buffer
,
708 "<column name=\"%s\">%s</column>",
713 while (!feof (fp
.get ()));
716 buffer_grow_str (&buffer
, "</item>");
719 buffer_grow_str0 (&buffer
, "</osdata>\n");
720 buf
= buffer_finish (&buffer
);
721 len_avail
= strlen (buf
);
724 if (offset
>= len_avail
)
726 /* Done. Get rid of the buffer. */
727 buffer_free (&buffer
);
733 if (len
> len_avail
- offset
)
734 len
= len_avail
- offset
;
735 memcpy (readbuf
, buf
+ offset
, len
);
740 /* Collect all the open file descriptors found in /proc and put the details
741 found about them into READBUF. */
744 linux_xfer_osdata_fds (gdb_byte
*readbuf
,
745 ULONGEST offset
, ULONGEST len
)
747 /* We make the process list snapshot when the object starts to be read. */
748 static const char *buf
;
749 static LONGEST len_avail
= -1;
750 static struct buffer buffer
;
756 if (len_avail
!= -1 && len_avail
!= 0)
757 buffer_free (&buffer
);
760 buffer_init (&buffer
);
761 buffer_grow_str (&buffer
, "<osdata type=\"files\">\n");
763 dirp
= opendir ("/proc");
768 while ((dp
= readdir (dirp
)) != NULL
)
771 char procentry
[sizeof ("/proc/4294967295")];
773 if (!isdigit (dp
->d_name
[0])
774 || NAMELEN (dp
) > sizeof ("4294967295") - 1)
777 xsnprintf (procentry
, sizeof (procentry
), "/proc/%s",
779 if (stat (procentry
, &statbuf
) == 0
780 && S_ISDIR (statbuf
.st_mode
))
787 pid
= atoi (dp
->d_name
);
788 command_from_pid (command
, sizeof (command
), pid
);
790 pathname
= xstrprintf ("/proc/%s/fd", dp
->d_name
);
791 dirp2
= opendir (pathname
);
797 while ((dp2
= readdir (dirp2
)) != NULL
)
803 if (!isdigit (dp2
->d_name
[0]))
806 fdname
= xstrprintf ("%s/%s", pathname
, dp2
->d_name
);
807 rslt
= readlink (fdname
, buf
, sizeof (buf
) - 1);
814 "<column name=\"pid\">%s</column>"
815 "<column name=\"command\">%s</column>"
816 "<column name=\"file descriptor\">%s</column>"
817 "<column name=\"name\">%s</column>"
822 (rslt
>= 0 ? buf
: dp2
->d_name
));
835 buffer_grow_str0 (&buffer
, "</osdata>\n");
836 buf
= buffer_finish (&buffer
);
837 len_avail
= strlen (buf
);
840 if (offset
>= len_avail
)
842 /* Done. Get rid of the buffer. */
843 buffer_free (&buffer
);
849 if (len
> len_avail
- offset
)
850 len
= len_avail
- offset
;
851 memcpy (readbuf
, buf
+ offset
, len
);
856 /* Returns the socket state STATE in textual form. */
859 format_socket_state (unsigned char state
)
861 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
878 case TCP_ESTABLISHED
:
879 return "ESTABLISHED";
908 struct sockaddr_in sin
;
909 struct sockaddr_in6 sin6
;
912 /* Auxiliary function used by linux_xfer_osdata_isocket. Formats
913 information for all open internet sockets of type FAMILY on the
914 system into BUFFER. If TCP is set, only TCP sockets are processed,
915 otherwise only UDP sockets are processed. */
918 print_sockets (unsigned short family
, int tcp
, struct buffer
*buffer
)
920 const char *proc_file
;
922 if (family
== AF_INET
)
923 proc_file
= tcp
? "/proc/net/tcp" : "/proc/net/udp";
924 else if (family
== AF_INET6
)
925 proc_file
= tcp
? "/proc/net/tcp6" : "/proc/net/udp6";
929 gdb_file_up fp
= gdb_fopen_cloexec (proc_file
, "r");
936 if (fgets (buf
, sizeof (buf
), fp
.get ()))
939 unsigned int local_port
, remote_port
, state
;
940 char local_address
[NI_MAXHOST
], remote_address
[NI_MAXHOST
];
944 #error "local_address and remote_address buffers too small"
947 result
= sscanf (buf
,
948 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
949 local_address
, &local_port
,
950 remote_address
, &remote_port
,
956 union socket_addr locaddr
, remaddr
;
958 char user
[UT_NAMESIZE
];
959 char local_service
[NI_MAXSERV
], remote_service
[NI_MAXSERV
];
961 if (family
== AF_INET
)
963 sscanf (local_address
, "%X",
964 &locaddr
.sin
.sin_addr
.s_addr
);
965 sscanf (remote_address
, "%X",
966 &remaddr
.sin
.sin_addr
.s_addr
);
968 locaddr
.sin
.sin_port
= htons (local_port
);
969 remaddr
.sin
.sin_port
= htons (remote_port
);
971 addr_size
= sizeof (struct sockaddr_in
);
975 sscanf (local_address
, "%8X%8X%8X%8X",
976 locaddr
.sin6
.sin6_addr
.s6_addr32
,
977 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
978 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
979 locaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
980 sscanf (remote_address
, "%8X%8X%8X%8X",
981 remaddr
.sin6
.sin6_addr
.s6_addr32
,
982 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 1,
983 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 2,
984 remaddr
.sin6
.sin6_addr
.s6_addr32
+ 3);
986 locaddr
.sin6
.sin6_port
= htons (local_port
);
987 remaddr
.sin6
.sin6_port
= htons (remote_port
);
989 locaddr
.sin6
.sin6_flowinfo
= 0;
990 remaddr
.sin6
.sin6_flowinfo
= 0;
991 locaddr
.sin6
.sin6_scope_id
= 0;
992 remaddr
.sin6
.sin6_scope_id
= 0;
994 addr_size
= sizeof (struct sockaddr_in6
);
997 locaddr
.sa
.sa_family
= remaddr
.sa
.sa_family
= family
;
999 result
= getnameinfo (&locaddr
.sa
, addr_size
,
1000 local_address
, sizeof (local_address
),
1001 local_service
, sizeof (local_service
),
1002 NI_NUMERICHOST
| NI_NUMERICSERV
1003 | (tcp
? 0 : NI_DGRAM
));
1007 result
= getnameinfo (&remaddr
.sa
, addr_size
,
1009 sizeof (remote_address
),
1011 sizeof (remote_service
),
1012 NI_NUMERICHOST
| NI_NUMERICSERV
1013 | (tcp
? 0 : NI_DGRAM
));
1017 user_from_uid (user
, sizeof (user
), uid
);
1022 "<column name=\"local address\">%s</column>"
1023 "<column name=\"local port\">%s</column>"
1024 "<column name=\"remote address\">%s</column>"
1025 "<column name=\"remote port\">%s</column>"
1026 "<column name=\"state\">%s</column>"
1027 "<column name=\"user\">%s</column>"
1028 "<column name=\"family\">%s</column>"
1029 "<column name=\"protocol\">%s</column>"
1035 format_socket_state (state
),
1037 (family
== AF_INET
) ? "INET" : "INET6",
1038 tcp
? "STREAM" : "DGRAM");
1042 while (!feof (fp
.get ()));
1046 /* Collect data about internet sockets and write it into READBUF. */
1049 linux_xfer_osdata_isockets (gdb_byte
*readbuf
,
1050 ULONGEST offset
, ULONGEST len
)
1052 static const char *buf
;
1053 static LONGEST len_avail
= -1;
1054 static struct buffer buffer
;
1058 if (len_avail
!= -1 && len_avail
!= 0)
1059 buffer_free (&buffer
);
1062 buffer_init (&buffer
);
1063 buffer_grow_str (&buffer
, "<osdata type=\"I sockets\">\n");
1065 print_sockets (AF_INET
, 1, &buffer
);
1066 print_sockets (AF_INET
, 0, &buffer
);
1067 print_sockets (AF_INET6
, 1, &buffer
);
1068 print_sockets (AF_INET6
, 0, &buffer
);
1070 buffer_grow_str0 (&buffer
, "</osdata>\n");
1071 buf
= buffer_finish (&buffer
);
1072 len_avail
= strlen (buf
);
1075 if (offset
>= len_avail
)
1077 /* Done. Get rid of the buffer. */
1078 buffer_free (&buffer
);
1084 if (len
> len_avail
- offset
)
1085 len
= len_avail
- offset
;
1086 memcpy (readbuf
, buf
+ offset
, len
);
1091 /* Converts the time SECONDS into textual form and copies it into a
1092 buffer TIME, with at most MAXLEN characters copied. */
1095 time_from_time_t (char *time
, int maxlen
, TIME_T seconds
)
1101 time_t t
= (time_t) seconds
;
1103 strncpy (time
, ctime (&t
), maxlen
);
1104 time
[maxlen
- 1] = '\0';
1108 /* Finds the group name for the group GID and copies it into GROUP.
1109 At most MAXLEN characters are copied. */
1112 group_from_gid (char *group
, int maxlen
, gid_t gid
)
1114 struct group
*grentry
= getgrgid (gid
);
1118 strncpy (group
, grentry
->gr_name
, maxlen
);
1119 /* Ensure that the group name is null-terminated. */
1120 group
[maxlen
- 1] = '\0';
1126 /* Collect data about shared memory recorded in /proc and write it
1130 linux_xfer_osdata_shm (gdb_byte
*readbuf
,
1131 ULONGEST offset
, ULONGEST len
)
1133 static const char *buf
;
1134 static LONGEST len_avail
= -1;
1135 static struct buffer buffer
;
1139 if (len_avail
!= -1 && len_avail
!= 0)
1140 buffer_free (&buffer
);
1143 buffer_init (&buffer
);
1144 buffer_grow_str (&buffer
, "<osdata type=\"shared memory\">\n");
1146 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
1153 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1159 int shmid
, size
, nattch
;
1160 TIME_T atime
, dtime
, ctime
;
1164 items_read
= sscanf (buf
,
1165 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
1166 &key
, &shmid
, &perms
, &size
,
1169 &uid
, &gid
, &cuid
, &cgid
,
1170 &atime
, &dtime
, &ctime
);
1172 if (items_read
== 14)
1174 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1175 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1176 char ccmd
[32], lcmd
[32];
1177 char atime_str
[32], dtime_str
[32], ctime_str
[32];
1179 user_from_uid (user
, sizeof (user
), uid
);
1180 group_from_gid (group
, sizeof (group
), gid
);
1181 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1182 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1184 command_from_pid (ccmd
, sizeof (ccmd
), cpid
);
1185 command_from_pid (lcmd
, sizeof (lcmd
), lpid
);
1187 time_from_time_t (atime_str
, sizeof (atime_str
), atime
);
1188 time_from_time_t (dtime_str
, sizeof (dtime_str
), dtime
);
1189 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1194 "<column name=\"key\">%d</column>"
1195 "<column name=\"shmid\">%d</column>"
1196 "<column name=\"permissions\">%o</column>"
1197 "<column name=\"size\">%d</column>"
1198 "<column name=\"creator command\">%s</column>"
1199 "<column name=\"last op. command\">%s</column>"
1200 "<column name=\"num attached\">%d</column>"
1201 "<column name=\"user\">%s</column>"
1202 "<column name=\"group\">%s</column>"
1203 "<column name=\"creator user\">%s</column>"
1204 "<column name=\"creator group\">%s</column>"
1205 "<column name=\"last shmat() time\">%s</column>"
1206 "<column name=\"last shmdt() time\">%s</column>"
1207 "<column name=\"last shmctl() time\">%s</column>"
1226 while (!feof (fp
.get ()));
1229 buffer_grow_str0 (&buffer
, "</osdata>\n");
1230 buf
= buffer_finish (&buffer
);
1231 len_avail
= strlen (buf
);
1234 if (offset
>= len_avail
)
1236 /* Done. Get rid of the buffer. */
1237 buffer_free (&buffer
);
1243 if (len
> len_avail
- offset
)
1244 len
= len_avail
- offset
;
1245 memcpy (readbuf
, buf
+ offset
, len
);
1250 /* Collect data about semaphores recorded in /proc and write it
1254 linux_xfer_osdata_sem (gdb_byte
*readbuf
,
1255 ULONGEST offset
, ULONGEST len
)
1257 static const char *buf
;
1258 static LONGEST len_avail
= -1;
1259 static struct buffer buffer
;
1263 if (len_avail
!= -1 && len_avail
!= 0)
1264 buffer_free (&buffer
);
1267 buffer_init (&buffer
);
1268 buffer_grow_str (&buffer
, "<osdata type=\"semaphores\">\n");
1270 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1277 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1282 unsigned int perms
, nsems
;
1284 TIME_T otime
, ctime
;
1287 items_read
= sscanf (buf
,
1288 "%d %d %o %u %d %d %d %d %lld %lld",
1289 &key
, &semid
, &perms
, &nsems
,
1290 &uid
, &gid
, &cuid
, &cgid
,
1293 if (items_read
== 10)
1295 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1296 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1297 char otime_str
[32], ctime_str
[32];
1299 user_from_uid (user
, sizeof (user
), uid
);
1300 group_from_gid (group
, sizeof (group
), gid
);
1301 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1302 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1304 time_from_time_t (otime_str
, sizeof (otime_str
), otime
);
1305 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1310 "<column name=\"key\">%d</column>"
1311 "<column name=\"semid\">%d</column>"
1312 "<column name=\"permissions\">%o</column>"
1313 "<column name=\"num semaphores\">%u</column>"
1314 "<column name=\"user\">%s</column>"
1315 "<column name=\"group\">%s</column>"
1316 "<column name=\"creator user\">%s</column>"
1317 "<column name=\"creator group\">%s</column>"
1318 "<column name=\"last semop() time\">%s</column>"
1319 "<column name=\"last semctl() time\">%s</column>"
1334 while (!feof (fp
.get ()));
1337 buffer_grow_str0 (&buffer
, "</osdata>\n");
1338 buf
= buffer_finish (&buffer
);
1339 len_avail
= strlen (buf
);
1342 if (offset
>= len_avail
)
1344 /* Done. Get rid of the buffer. */
1345 buffer_free (&buffer
);
1351 if (len
> len_avail
- offset
)
1352 len
= len_avail
- offset
;
1353 memcpy (readbuf
, buf
+ offset
, len
);
1358 /* Collect data about message queues recorded in /proc and write it
1362 linux_xfer_osdata_msg (gdb_byte
*readbuf
,
1363 ULONGEST offset
, ULONGEST len
)
1365 static const char *buf
;
1366 static LONGEST len_avail
= -1;
1367 static struct buffer buffer
;
1371 if (len_avail
!= -1 && len_avail
!= 0)
1372 buffer_free (&buffer
);
1375 buffer_init (&buffer
);
1376 buffer_grow_str (&buffer
, "<osdata type=\"message queues\">\n");
1378 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1385 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1391 unsigned int perms
, cbytes
, qnum
;
1393 TIME_T stime
, rtime
, ctime
;
1396 items_read
= sscanf (buf
,
1397 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1398 &key
, &msqid
, &perms
, &cbytes
, &qnum
,
1399 &lspid
, &lrpid
, &uid
, &gid
, &cuid
, &cgid
,
1400 &stime
, &rtime
, &ctime
);
1402 if (items_read
== 14)
1404 char user
[UT_NAMESIZE
], group
[UT_NAMESIZE
];
1405 char cuser
[UT_NAMESIZE
], cgroup
[UT_NAMESIZE
];
1406 char lscmd
[32], lrcmd
[32];
1407 char stime_str
[32], rtime_str
[32], ctime_str
[32];
1409 user_from_uid (user
, sizeof (user
), uid
);
1410 group_from_gid (group
, sizeof (group
), gid
);
1411 user_from_uid (cuser
, sizeof (cuser
), cuid
);
1412 group_from_gid (cgroup
, sizeof (cgroup
), cgid
);
1414 command_from_pid (lscmd
, sizeof (lscmd
), lspid
);
1415 command_from_pid (lrcmd
, sizeof (lrcmd
), lrpid
);
1417 time_from_time_t (stime_str
, sizeof (stime_str
), stime
);
1418 time_from_time_t (rtime_str
, sizeof (rtime_str
), rtime
);
1419 time_from_time_t (ctime_str
, sizeof (ctime_str
), ctime
);
1424 "<column name=\"key\">%d</column>"
1425 "<column name=\"msqid\">%d</column>"
1426 "<column name=\"permissions\">%o</column>"
1427 "<column name=\"num used bytes\">%u</column>"
1428 "<column name=\"num messages\">%u</column>"
1429 "<column name=\"last msgsnd() command\">%s</column>"
1430 "<column name=\"last msgrcv() command\">%s</column>"
1431 "<column name=\"user\">%s</column>"
1432 "<column name=\"group\">%s</column>"
1433 "<column name=\"creator user\">%s</column>"
1434 "<column name=\"creator group\">%s</column>"
1435 "<column name=\"last msgsnd() time\">%s</column>"
1436 "<column name=\"last msgrcv() time\">%s</column>"
1437 "<column name=\"last msgctl() time\">%s</column>"
1456 while (!feof (fp
.get ()));
1459 buffer_grow_str0 (&buffer
, "</osdata>\n");
1460 buf
= buffer_finish (&buffer
);
1461 len_avail
= strlen (buf
);
1464 if (offset
>= len_avail
)
1466 /* Done. Get rid of the buffer. */
1467 buffer_free (&buffer
);
1473 if (len
> len_avail
- offset
)
1474 len
= len_avail
- offset
;
1475 memcpy (readbuf
, buf
+ offset
, len
);
1480 /* Collect data about loaded kernel modules and write it into
1484 linux_xfer_osdata_modules (gdb_byte
*readbuf
,
1485 ULONGEST offset
, ULONGEST len
)
1487 static const char *buf
;
1488 static LONGEST len_avail
= -1;
1489 static struct buffer buffer
;
1493 if (len_avail
!= -1 && len_avail
!= 0)
1494 buffer_free (&buffer
);
1497 buffer_init (&buffer
);
1498 buffer_grow_str (&buffer
, "<osdata type=\"modules\">\n");
1500 gdb_file_up fp
= gdb_fopen_cloexec ("/proc/modules", "r");
1507 if (fgets (buf
, sizeof (buf
), fp
.get ()))
1509 char *name
, *dependencies
, *status
, *tmp
;
1511 unsigned long long address
;
1514 name
= strtok (buf
, " ");
1518 tmp
= strtok (NULL
, " ");
1521 if (sscanf (tmp
, "%u", &size
) != 1)
1524 tmp
= strtok (NULL
, " ");
1527 if (sscanf (tmp
, "%d", &uses
) != 1)
1530 dependencies
= strtok (NULL
, " ");
1531 if (dependencies
== NULL
)
1534 status
= strtok (NULL
, " ");
1538 tmp
= strtok (NULL
, "\n");
1541 if (sscanf (tmp
, "%llx", &address
) != 1)
1547 "<column name=\"name\">%s</column>"
1548 "<column name=\"size\">%u</column>"
1549 "<column name=\"num uses\">%d</column>"
1550 "<column name=\"dependencies\">%s</column>"
1551 "<column name=\"status\">%s</column>"
1552 "<column name=\"address\">%llx</column>"
1562 while (!feof (fp
.get ()));
1565 buffer_grow_str0 (&buffer
, "</osdata>\n");
1566 buf
= buffer_finish (&buffer
);
1567 len_avail
= strlen (buf
);
1570 if (offset
>= len_avail
)
1572 /* Done. Get rid of the buffer. */
1573 buffer_free (&buffer
);
1579 if (len
> len_avail
- offset
)
1580 len
= len_avail
- offset
;
1581 memcpy (readbuf
, buf
+ offset
, len
);
1586 struct osdata_type
{
1589 const char *description
;
1590 LONGEST (*getter
) (gdb_byte
*readbuf
, ULONGEST offset
, ULONGEST len
);
1591 } osdata_table
[] = {
1592 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1593 linux_xfer_osdata_cpus
},
1594 { "files", "File descriptors", "Listing of all file descriptors",
1595 linux_xfer_osdata_fds
},
1596 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1597 linux_xfer_osdata_modules
},
1598 { "msg", "Message queues", "Listing of all message queues",
1599 linux_xfer_osdata_msg
},
1600 { "processes", "Processes", "Listing of all processes",
1601 linux_xfer_osdata_processes
},
1602 { "procgroups", "Process groups", "Listing of all process groups",
1603 linux_xfer_osdata_processgroups
},
1604 { "semaphores", "Semaphores", "Listing of all semaphores",
1605 linux_xfer_osdata_sem
},
1606 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1607 linux_xfer_osdata_shm
},
1608 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1609 linux_xfer_osdata_isockets
},
1610 { "threads", "Threads", "Listing of all threads",
1611 linux_xfer_osdata_threads
},
1612 { NULL
, NULL
, NULL
}
1616 linux_common_xfer_osdata (const char *annex
, gdb_byte
*readbuf
,
1617 ULONGEST offset
, ULONGEST len
)
1619 if (!annex
|| *annex
== '\0')
1621 static const char *buf
;
1622 static LONGEST len_avail
= -1;
1623 static struct buffer buffer
;
1629 if (len_avail
!= -1 && len_avail
!= 0)
1630 buffer_free (&buffer
);
1633 buffer_init (&buffer
);
1634 buffer_grow_str (&buffer
, "<osdata type=\"types\">\n");
1636 for (i
= 0; osdata_table
[i
].type
; ++i
)
1640 "<column name=\"Type\">%s</column>"
1641 "<column name=\"Description\">%s</column>"
1642 "<column name=\"Title\">%s</column>"
1644 osdata_table
[i
].type
,
1645 osdata_table
[i
].description
,
1646 osdata_table
[i
].title
);
1648 buffer_grow_str0 (&buffer
, "</osdata>\n");
1649 buf
= buffer_finish (&buffer
);
1650 len_avail
= strlen (buf
);
1653 if (offset
>= len_avail
)
1655 /* Done. Get rid of the buffer. */
1656 buffer_free (&buffer
);
1662 if (len
> len_avail
- offset
)
1663 len
= len_avail
- offset
;
1664 memcpy (readbuf
, buf
+ offset
, len
);
1672 for (i
= 0; osdata_table
[i
].type
; ++i
)
1674 if (strcmp (annex
, osdata_table
[i
].type
) == 0)
1676 gdb_assert (readbuf
);
1678 return (osdata_table
[i
].getter
) (readbuf
, offset
, len
);