GDBserver
Loading...
Searching...
No Matches
linux-osdata.c
Go to the documentation of this file.
1/* Linux-specific functions to retrieve OS data.
2
3 Copyright (C) 2009-2023 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
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.
11
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.
16
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/>. */
19
20#include "gdbsupport/common-defs.h"
21#include "linux-osdata.h"
22
23#include <sys/types.h>
24#include <sys/sysinfo.h>
25#include <ctype.h>
26#include <utmp.h>
27#include <time.h>
28#include <unistd.h>
29#include <pwd.h>
30#include <grp.h>
31#include <netdb.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34
35#include "gdbsupport/xml-utils.h"
36#include "gdbsupport/buffer.h"
37#include <dirent.h>
38#include <sys/stat.h>
39#include "gdbsupport/filestuff.h"
40#include <algorithm>
41
42#define NAMELEN(dirent) strlen ((dirent)->d_name)
43
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
46 consistently. */
47
48typedef long long PID_T;
49
50/* Define TIME_T to be at least as large as time_t, so that reading
51 time values embedded in /proc works consistently. */
52
53typedef long long TIME_T;
54
55#define MAX_PID_T_STRLEN (sizeof ("-9223372036854775808") - 1)
56
57/* Returns the CPU core that thread PTID is currently running on. */
58
59/* Compute and return the processor core of a given thread. */
60
61int
63{
64 char filename[sizeof ("/proc//task//stat") + 2 * MAX_PID_T_STRLEN];
65 int core;
66
67 sprintf (filename, "/proc/%lld/task/%lld/stat",
68 (PID_T) ptid.pid (), (PID_T) ptid.lwp ());
69
70 gdb::optional<std::string> content = read_text_file_to_string (filename);
71 if (!content.has_value ())
72 return -1;
73
74 /* ps command also relies on no trailing fields ever contain ')'. */
75 std::string::size_type pos = content->find_last_of (')');
76 if (pos == std::string::npos)
77 return -1;
78
79 /* If the first field after program name has index 0, then core number is
80 the field with index 36 (so, the 37th). There's no constant for that
81 anywhere. */
82 for (int i = 0; i < 37; ++i)
83 {
84 /* Find separator. */
85 pos = content->find_first_of (' ', pos);
86 if (pos == std::string::npos)
87 return {};
88
89 /* Find beginning of field. */
90 pos = content->find_first_not_of (' ', pos);
91 if (pos == std::string::npos)
92 return {};
93 }
94
95 if (sscanf (&(*content)[pos], "%d", &core) == 0)
96 core = -1;
97
98 return core;
99}
100
101/* Finds the command-line of process PID and copies it into COMMAND.
102 At most MAXLEN characters are copied. If the command-line cannot
103 be found, PID is copied into command in text-form. */
104
105static void
106command_from_pid (char *command, int maxlen, PID_T pid)
107{
108 std::string stat_path = string_printf ("/proc/%lld/stat", pid);
109 gdb_file_up fp = gdb_fopen_cloexec (stat_path, "r");
110
111 command[0] = '\0';
112
113 if (fp)
114 {
115 /* sizeof (cmd) should be greater or equal to TASK_COMM_LEN (in
116 include/linux/sched.h in the Linux kernel sources) plus two
117 (for the brackets). */
118 char cmd[18];
119 PID_T stat_pid;
120 int items_read = fscanf (fp.get (), "%lld %17s", &stat_pid, cmd);
121
122 if (items_read == 2 && pid == stat_pid)
123 {
124 cmd[strlen (cmd) - 1] = '\0'; /* Remove trailing parenthesis. */
125 strncpy (command, cmd + 1, maxlen); /* Ignore leading parenthesis. */
126 }
127 }
128 else
129 {
130 /* Return the PID if a /proc entry for the process cannot be found. */
131 snprintf (command, maxlen, "%lld", pid);
132 }
133
134 command[maxlen - 1] = '\0'; /* Ensure string is null-terminated. */
135}
136
137/* Returns the command-line of the process with the given PID. The
138 returned string needs to be freed using xfree after use. */
139
140static char *
142{
143 std::string pathname = string_printf ("/proc/%lld/cmdline", pid);
144 char *commandline = NULL;
145 gdb_file_up f = gdb_fopen_cloexec (pathname, "r");
146
147 if (f)
148 {
149 size_t len = 0;
150
151 while (!feof (f.get ()))
152 {
153 char buf[1024];
154 size_t read_bytes = fread (buf, 1, sizeof (buf), f.get ());
155
156 if (read_bytes)
157 {
158 commandline = (char *) xrealloc (commandline, len + read_bytes + 1);
159 memcpy (commandline + len, buf, read_bytes);
160 len += read_bytes;
161 }
162 }
163
164 if (commandline)
165 {
166 size_t i;
167
168 /* Replace null characters with spaces. */
169 for (i = 0; i < len; ++i)
170 if (commandline[i] == '\0')
171 commandline[i] = ' ';
172
173 commandline[len] = '\0';
174 }
175 else
176 {
177 /* Return the command in square brackets if the command-line
178 is empty. */
179 commandline = (char *) xmalloc (32);
180 commandline[0] = '[';
181 command_from_pid (commandline + 1, 31, pid);
182
183 len = strlen (commandline);
184 if (len < 31)
185 strcat (commandline, "]");
186 }
187 }
188
189 return commandline;
190}
191
192/* Finds the user name for the user UID and copies it into USER. At
193 most MAXLEN characters are copied. */
194
195static void
196user_from_uid (char *user, int maxlen, uid_t uid)
197{
198 struct passwd *pwentry;
199 char buf[1024];
200 struct passwd pwd;
201 getpwuid_r (uid, &pwd, buf, sizeof (buf), &pwentry);
202
203 if (pwentry)
204 {
205 strncpy (user, pwentry->pw_name, maxlen - 1);
206 /* Ensure that the user name is null-terminated. */
207 user[maxlen - 1] = '\0';
208 }
209 else
210 user[0] = '\0';
211}
212
213/* Finds the owner of process PID and returns the user id in OWNER.
214 Returns 0 if the owner was found, -1 otherwise. */
215
216static int
217get_process_owner (uid_t *owner, PID_T pid)
218{
219 struct stat statbuf;
220 char procentry[sizeof ("/proc/") + MAX_PID_T_STRLEN];
221
222 sprintf (procentry, "/proc/%lld", pid);
223
224 if (stat (procentry, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
225 {
226 *owner = statbuf.st_uid;
227 return 0;
228 }
229 else
230 return -1;
231}
232
233/* Find the CPU cores used by process PID and return them in CORES.
234 CORES points to an array of NUM_CORES elements. */
235
236static int
237get_cores_used_by_process (PID_T pid, int *cores, const int num_cores)
238{
239 char taskdir[sizeof ("/proc/") + MAX_PID_T_STRLEN + sizeof ("/task") - 1];
240 DIR *dir;
241 struct dirent *dp;
242 int task_count = 0;
243
244 sprintf (taskdir, "/proc/%lld/task", pid);
245 dir = opendir (taskdir);
246 if (dir)
247 {
248 while ((dp = readdir (dir)) != NULL)
249 {
250 PID_T tid;
251 int core;
252
253 if (!isdigit (dp->d_name[0])
254 || NAMELEN (dp) > MAX_PID_T_STRLEN)
255 continue;
256
257 sscanf (dp->d_name, "%lld", &tid);
258 core = linux_common_core_of_thread (ptid_t ((pid_t) pid,
259 (pid_t) tid));
260
261 if (core >= 0 && core < num_cores)
262 {
263 ++cores[core];
264 ++task_count;
265 }
266 }
267
268 closedir (dir);
269 }
270
271 return task_count;
272}
273
274/* get_core_array_size helper that uses /sys/devices/system/cpu/possible. */
275
276static gdb::optional<size_t>
278{
279 gdb::optional<std::string> possible
280 = read_text_file_to_string ("/sys/devices/system/cpu/possible");
281
282 if (!possible.has_value ())
283 return {};
284
285 /* The format is documented here:
286
287 https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst
288
289 For the purpose of this function, we assume the file can contain a complex
290 set of ranges, like `2,4-31,32-63`. Read all number, disregarding commands
291 and dashes, in order to find the largest possible core number. The size
292 of the array to allocate is that plus one. */
293
294 unsigned long max_id = 0;
295 for (std::string::size_type start = 0; start < possible->size ();)
296 {
297 const char *start_p = &(*possible)[start];
298 char *end_p;
299
300 /* Parse one number. */
301 errno = 0;
302 unsigned long id = strtoul (start_p, &end_p, 10);
303 if (errno != 0)
304 return {};
305
306 max_id = std::max (max_id, id);
307
308 start += end_p - start_p;
309 gdb_assert (start <= possible->size ());
310
311 /* Skip comma, dash, or new line (if we are at the end). */
312 ++start;
313 }
314
315 return max_id + 1;
316}
317
318/* Return the array size to allocate in order to be able to index it using
319 CPU core numbers. This may be more than the actual number of cores if
320 the core numbers are not contiguous. */
321
322static size_t
324{
325 /* Using /sys/.../possible is prefered, because it handles the case where
326 we are in a container that has access to a subset of the host's cores.
327 It will return a size that considers all the CPU cores available to the
328 host. If that fials for some reason, fall back to sysconf. */
329 gdb::optional<size_t> count = get_core_array_size_using_sys_possible ();
330 if (count.has_value ())
331 return *count;
332
333 return sysconf (_SC_NPROCESSORS_ONLN);
334}
335
336static std::string
338{
339 DIR *dirp;
340 std::string buffer = "<osdata type=\"processes\">\n";
341
342 dirp = opendir ("/proc");
343 if (dirp)
344 {
345 const int core_array_size = get_core_array_size ();
346 struct dirent *dp;
347
348 while ((dp = readdir (dirp)) != NULL)
349 {
350 PID_T pid;
351 uid_t owner;
352 char user[UT_NAMESIZE];
353 char *command_line;
354 int *cores;
355 int task_count;
356 std::string cores_str;
357 int i;
358
359 if (!isdigit (dp->d_name[0])
360 || NAMELEN (dp) > MAX_PID_T_STRLEN)
361 continue;
362
363 sscanf (dp->d_name, "%lld", &pid);
364 command_line = commandline_from_pid (pid);
365
366 if (get_process_owner (&owner, pid) == 0)
367 user_from_uid (user, sizeof (user), owner);
368 else
369 strcpy (user, "?");
370
371 /* Find CPU cores used by the process. */
372 cores = XCNEWVEC (int, core_array_size);
373 task_count = get_cores_used_by_process (pid, cores, core_array_size);
374
375 for (i = 0; i < core_array_size && task_count > 0; ++i)
376 if (cores[i])
377 {
378 string_appendf (cores_str, "%d", i);
379
380 task_count -= cores[i];
381 if (task_count > 0)
382 cores_str += ",";
383 }
384
385 xfree (cores);
386
387 string_xml_appendf
388 (buffer,
389 "<item>"
390 "<column name=\"pid\">%lld</column>"
391 "<column name=\"user\">%s</column>"
392 "<column name=\"command\">%s</column>"
393 "<column name=\"cores\">%s</column>"
394 "</item>",
395 pid,
396 user,
397 command_line ? command_line : "",
398 cores_str.c_str());
399
400 xfree (command_line);
401 }
402
403 closedir (dirp);
404 }
405
406 buffer += "</osdata>\n";
407
408 return buffer;
409}
410
411/* A simple PID/PGID pair. */
412
414{
416 : pid (pid_), pgid (pgid_)
417 {}
418
419 /* Return true if this pid is the leader of its process group. */
420
421 bool is_leader () const
422 {
423 return pid == pgid;
424 }
425
426 bool operator< (const pid_pgid_entry &other) const
427 {
428 /* Sort by PGID. */
429 if (this->pgid != other.pgid)
430 return this->pgid < other.pgid;
431
432 /* Process group leaders always come first... */
433 if (this->is_leader ())
434 {
435 if (!other.is_leader ())
436 return true;
437 }
438 else if (other.is_leader ())
439 return false;
440
441 /* ...else sort by PID. */
442 return this->pid < other.pid;
443 }
444
446};
447
448/* Collect all process groups from /proc in BUFFER. */
449
450static std::string
452{
453 DIR *dirp;
454 std::string buffer = "<osdata type=\"process groups\">\n";
455
456 dirp = opendir ("/proc");
457 if (dirp)
458 {
459 std::vector<pid_pgid_entry> process_list;
460 struct dirent *dp;
461
462 process_list.reserve (512);
463
464 /* Build list consisting of PIDs followed by their
465 associated PGID. */
466 while ((dp = readdir (dirp)) != NULL)
467 {
468 PID_T pid, pgid;
469
470 if (!isdigit (dp->d_name[0])
471 || NAMELEN (dp) > MAX_PID_T_STRLEN)
472 continue;
473
474 sscanf (dp->d_name, "%lld", &pid);
475 pgid = getpgid (pid);
476
477 if (pgid > 0)
478 process_list.emplace_back (pid, pgid);
479 }
480
481 closedir (dirp);
482
483 /* Sort the process list. */
484 std::sort (process_list.begin (), process_list.end ());
485
486 for (const pid_pgid_entry &entry : process_list)
487 {
488 PID_T pid = entry.pid;
489 PID_T pgid = entry.pgid;
490 char leader_command[32];
491 char *command_line;
492
493 command_from_pid (leader_command, sizeof (leader_command), pgid);
494 command_line = commandline_from_pid (pid);
495
496 string_xml_appendf
497 (buffer,
498 "<item>"
499 "<column name=\"pgid\">%lld</column>"
500 "<column name=\"leader command\">%s</column>"
501 "<column name=\"pid\">%lld</column>"
502 "<column name=\"command line\">%s</column>"
503 "</item>",
504 pgid,
505 leader_command,
506 pid,
507 command_line ? command_line : "");
508
509 xfree (command_line);
510 }
511 }
512
513 buffer += "</osdata>\n";
514
515 return buffer;
516}
517
518/* Collect all the threads in /proc by iterating through processes and
519 then tasks within each process. */
520
521static std::string
523{
524 DIR *dirp;
525 std::string buffer = "<osdata type=\"threads\">\n";
526
527 dirp = opendir ("/proc");
528 if (dirp)
529 {
530 struct dirent *dp;
531
532 while ((dp = readdir (dirp)) != NULL)
533 {
534 struct stat statbuf;
535 char procentry[sizeof ("/proc/4294967295")];
536
537 if (!isdigit (dp->d_name[0])
538 || NAMELEN (dp) > sizeof ("4294967295") - 1)
539 continue;
540
541 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
542 dp->d_name);
543 if (stat (procentry, &statbuf) == 0
544 && S_ISDIR (statbuf.st_mode))
545 {
546 DIR *dirp2;
547 PID_T pid;
548 char command[32];
549
550 std::string pathname
551 = string_printf ("/proc/%s/task", dp->d_name);
552
553 pid = atoi (dp->d_name);
554 command_from_pid (command, sizeof (command), pid);
555
556 dirp2 = opendir (pathname.c_str ());
557
558 if (dirp2)
559 {
560 struct dirent *dp2;
561
562 while ((dp2 = readdir (dirp2)) != NULL)
563 {
564 PID_T tid;
565 int core;
566
567 if (!isdigit (dp2->d_name[0])
568 || NAMELEN (dp2) > sizeof ("4294967295") - 1)
569 continue;
570
571 tid = atoi (dp2->d_name);
572 core = linux_common_core_of_thread (ptid_t (pid, tid));
573
574 string_xml_appendf
575 (buffer,
576 "<item>"
577 "<column name=\"pid\">%lld</column>"
578 "<column name=\"command\">%s</column>"
579 "<column name=\"tid\">%lld</column>"
580 "<column name=\"core\">%d</column>"
581 "</item>",
582 pid,
583 command,
584 tid,
585 core);
586 }
587
588 closedir (dirp2);
589 }
590 }
591 }
592
593 closedir (dirp);
594 }
595
596 buffer += "</osdata>\n";
597
598 return buffer;
599}
600
601/* Collect data about the cpus/cores on the system in BUFFER. */
602
603static std::string
605{
606 int first_item = 1;
607 std::string buffer = "<osdata type=\"cpus\">\n";
608
609 gdb_file_up fp = gdb_fopen_cloexec ("/proc/cpuinfo", "r");
610 if (fp != NULL)
611 {
612 char buf[8192];
613
614 do
615 {
616 if (fgets (buf, sizeof (buf), fp.get ()))
617 {
618 char *key, *value;
619 int i = 0;
620
621 char *saveptr;
622 key = strtok_r (buf, ":", &saveptr);
623 if (key == NULL)
624 continue;
625
626 value = strtok_r (NULL, ":", &saveptr);
627 if (value == NULL)
628 continue;
629
630 while (key[i] != '\t' && key[i] != '\0')
631 i++;
632
633 key[i] = '\0';
634
635 i = 0;
636 while (value[i] != '\t' && value[i] != '\0')
637 i++;
638
639 value[i] = '\0';
640
641 if (strcmp (key, "processor") == 0)
642 {
643 if (first_item)
644 buffer += "<item>";
645 else
646 buffer += "</item><item>";
647
648 first_item = 0;
649 }
650
651 string_xml_appendf (buffer,
652 "<column name=\"%s\">%s</column>",
653 key,
654 value);
655 }
656 }
657 while (!feof (fp.get ()));
658
659 if (first_item == 0)
660 buffer += "</item>";
661 }
662
663 buffer += "</osdata>\n";
664
665 return buffer;
666}
667
668/* Collect all the open file descriptors found in /proc and put the details
669 found about them into BUFFER. */
670
671static std::string
673{
674 DIR *dirp;
675 std::string buffer = "<osdata type=\"files\">\n";
676
677 dirp = opendir ("/proc");
678 if (dirp)
679 {
680 struct dirent *dp;
681
682 while ((dp = readdir (dirp)) != NULL)
683 {
684 struct stat statbuf;
685 char procentry[sizeof ("/proc/4294967295")];
686
687 if (!isdigit (dp->d_name[0])
688 || NAMELEN (dp) > sizeof ("4294967295") - 1)
689 continue;
690
691 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
692 dp->d_name);
693 if (stat (procentry, &statbuf) == 0
694 && S_ISDIR (statbuf.st_mode))
695 {
696 DIR *dirp2;
697 PID_T pid;
698 char command[32];
699
700 pid = atoi (dp->d_name);
701 command_from_pid (command, sizeof (command), pid);
702
703 std::string pathname
704 = string_printf ("/proc/%s/fd", dp->d_name);
705 dirp2 = opendir (pathname.c_str ());
706
707 if (dirp2)
708 {
709 struct dirent *dp2;
710
711 while ((dp2 = readdir (dirp2)) != NULL)
712 {
713 char buf[1000];
714 ssize_t rslt;
715
716 if (!isdigit (dp2->d_name[0]))
717 continue;
718
719 std::string fdname
720 = string_printf ("%s/%s", pathname.c_str (),
721 dp2->d_name);
722 rslt = readlink (fdname.c_str (), buf,
723 sizeof (buf) - 1);
724 if (rslt >= 0)
725 buf[rslt] = '\0';
726
727 string_xml_appendf
728 (buffer,
729 "<item>"
730 "<column name=\"pid\">%s</column>"
731 "<column name=\"command\">%s</column>"
732 "<column name=\"file descriptor\">%s</column>"
733 "<column name=\"name\">%s</column>"
734 "</item>",
735 dp->d_name,
736 command,
737 dp2->d_name,
738 (rslt >= 0 ? buf : dp2->d_name));
739 }
740
741 closedir (dirp2);
742 }
743 }
744 }
745
746 closedir (dirp);
747 }
748
749 buffer += "</osdata>\n";
750
751 return buffer;
752}
753
754/* Returns the socket state STATE in textual form. */
755
756static const char *
757format_socket_state (unsigned char state)
758{
759 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
760 enum {
761 TCP_ESTABLISHED = 1,
762 TCP_SYN_SENT,
763 TCP_SYN_RECV,
764 TCP_FIN_WAIT1,
765 TCP_FIN_WAIT2,
766 TCP_TIME_WAIT,
767 TCP_CLOSE,
768 TCP_CLOSE_WAIT,
769 TCP_LAST_ACK,
770 TCP_LISTEN,
771 TCP_CLOSING
772 };
773
774 switch (state)
775 {
776 case TCP_ESTABLISHED:
777 return "ESTABLISHED";
778 case TCP_SYN_SENT:
779 return "SYN_SENT";
780 case TCP_SYN_RECV:
781 return "SYN_RECV";
782 case TCP_FIN_WAIT1:
783 return "FIN_WAIT1";
784 case TCP_FIN_WAIT2:
785 return "FIN_WAIT2";
786 case TCP_TIME_WAIT:
787 return "TIME_WAIT";
788 case TCP_CLOSE:
789 return "CLOSE";
790 case TCP_CLOSE_WAIT:
791 return "CLOSE_WAIT";
792 case TCP_LAST_ACK:
793 return "LAST_ACK";
794 case TCP_LISTEN:
795 return "LISTEN";
796 case TCP_CLOSING:
797 return "CLOSING";
798 default:
799 return "(unknown)";
800 }
801}
802
804 {
805 struct sockaddr sa;
806 struct sockaddr_in sin;
807 struct sockaddr_in6 sin6;
808 };
809
810/* Auxiliary function used by linux_xfer_osdata_isocket. Formats
811 information for all open internet sockets of type FAMILY on the
812 system into BUFFER. If TCP is set, only TCP sockets are processed,
813 otherwise only UDP sockets are processed. */
814
815static void
816print_sockets (unsigned short family, int tcp, std::string &buffer)
817{
818 const char *proc_file;
819
820 if (family == AF_INET)
821 proc_file = tcp ? "/proc/net/tcp" : "/proc/net/udp";
822 else if (family == AF_INET6)
823 proc_file = tcp ? "/proc/net/tcp6" : "/proc/net/udp6";
824 else
825 return;
826
827 gdb_file_up fp = gdb_fopen_cloexec (proc_file, "r");
828 if (fp)
829 {
830 char buf[8192];
831
832 do
833 {
834 if (fgets (buf, sizeof (buf), fp.get ()))
835 {
836 uid_t uid;
837 unsigned int local_port, remote_port, state;
838 char local_address[NI_MAXHOST], remote_address[NI_MAXHOST];
839 int result;
840
841#if NI_MAXHOST <= 32
842#error "local_address and remote_address buffers too small"
843#endif
844
845 result = sscanf (buf,
846 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
847 local_address, &local_port,
848 remote_address, &remote_port,
849 &state,
850 &uid);
851
852 if (result == 6)
853 {
854 union socket_addr locaddr, remaddr;
855 size_t addr_size;
856 char user[UT_NAMESIZE];
857 char local_service[NI_MAXSERV], remote_service[NI_MAXSERV];
858
859 if (family == AF_INET)
860 {
861 sscanf (local_address, "%X",
862 &locaddr.sin.sin_addr.s_addr);
863 sscanf (remote_address, "%X",
864 &remaddr.sin.sin_addr.s_addr);
865
866 locaddr.sin.sin_port = htons (local_port);
867 remaddr.sin.sin_port = htons (remote_port);
868
869 addr_size = sizeof (struct sockaddr_in);
870 }
871 else
872 {
873 sscanf (local_address, "%8X%8X%8X%8X",
874 locaddr.sin6.sin6_addr.s6_addr32,
875 locaddr.sin6.sin6_addr.s6_addr32 + 1,
876 locaddr.sin6.sin6_addr.s6_addr32 + 2,
877 locaddr.sin6.sin6_addr.s6_addr32 + 3);
878 sscanf (remote_address, "%8X%8X%8X%8X",
879 remaddr.sin6.sin6_addr.s6_addr32,
880 remaddr.sin6.sin6_addr.s6_addr32 + 1,
881 remaddr.sin6.sin6_addr.s6_addr32 + 2,
882 remaddr.sin6.sin6_addr.s6_addr32 + 3);
883
884 locaddr.sin6.sin6_port = htons (local_port);
885 remaddr.sin6.sin6_port = htons (remote_port);
886
887 locaddr.sin6.sin6_flowinfo = 0;
888 remaddr.sin6.sin6_flowinfo = 0;
889 locaddr.sin6.sin6_scope_id = 0;
890 remaddr.sin6.sin6_scope_id = 0;
891
892 addr_size = sizeof (struct sockaddr_in6);
893 }
894
895 locaddr.sa.sa_family = remaddr.sa.sa_family = family;
896
897 result = getnameinfo (&locaddr.sa, addr_size,
898 local_address, sizeof (local_address),
899 local_service, sizeof (local_service),
900 NI_NUMERICHOST | NI_NUMERICSERV
901 | (tcp ? 0 : NI_DGRAM));
902 if (result)
903 continue;
904
905 result = getnameinfo (&remaddr.sa, addr_size,
906 remote_address,
907 sizeof (remote_address),
908 remote_service,
909 sizeof (remote_service),
910 NI_NUMERICHOST | NI_NUMERICSERV
911 | (tcp ? 0 : NI_DGRAM));
912 if (result)
913 continue;
914
915 user_from_uid (user, sizeof (user), uid);
916
917 string_xml_appendf
918 (buffer,
919 "<item>"
920 "<column name=\"local address\">%s</column>"
921 "<column name=\"local port\">%s</column>"
922 "<column name=\"remote address\">%s</column>"
923 "<column name=\"remote port\">%s</column>"
924 "<column name=\"state\">%s</column>"
925 "<column name=\"user\">%s</column>"
926 "<column name=\"family\">%s</column>"
927 "<column name=\"protocol\">%s</column>"
928 "</item>",
929 local_address,
930 local_service,
931 remote_address,
932 remote_service,
933 format_socket_state (state),
934 user,
935 (family == AF_INET) ? "INET" : "INET6",
936 tcp ? "STREAM" : "DGRAM");
937 }
938 }
939 }
940 while (!feof (fp.get ()));
941 }
942}
943
944/* Collect data about internet sockets and write it into BUFFER. */
945
946static std::string
948{
949 std::string buffer = "<osdata type=\"I sockets\">\n";
950
951 print_sockets (AF_INET, 1, buffer);
952 print_sockets (AF_INET, 0, buffer);
953 print_sockets (AF_INET6, 1, buffer);
954 print_sockets (AF_INET6, 0, buffer);
955
956 buffer += "</osdata>\n";
957
958 return buffer;
959}
960
961/* Converts the time SECONDS into textual form and copies it into a
962 buffer TIME, with at most MAXLEN characters copied. */
963
964static void
965time_from_time_t (char *time, int maxlen, TIME_T seconds)
966{
967 if (!seconds)
968 time[0] = '\0';
969 else
970 {
971 time_t t = (time_t) seconds;
972
973 /* Per the ctime_r manpage, this buffer needs to be at least 26
974 characters long. */
975 char buf[30];
976 const char *time_str = ctime_r (&t, buf);
977 strncpy (time, time_str, maxlen - 1);
978 time[maxlen - 1] = '\0';
979 }
980}
981
982/* Finds the group name for the group GID and copies it into GROUP.
983 At most MAXLEN characters are copied. */
984
985static void
986group_from_gid (char *group, int maxlen, gid_t gid)
987{
988 struct group *grentry = getgrgid (gid);
989
990 if (grentry)
991 {
992 strncpy (group, grentry->gr_name, maxlen - 1);
993 /* Ensure that the group name is null-terminated. */
994 group[maxlen - 1] = '\0';
995 }
996 else
997 group[0] = '\0';
998}
999
1000/* Collect data about shared memory recorded in /proc and write it
1001 into BUFFER. */
1002
1003static std::string
1005{
1006 std::string buffer = "<osdata type=\"shared memory\">\n";
1007
1008 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
1009 if (fp)
1010 {
1011 char buf[8192];
1012
1013 do
1014 {
1015 if (fgets (buf, sizeof (buf), fp.get ()))
1016 {
1017 key_t key;
1018 uid_t uid, cuid;
1019 gid_t gid, cgid;
1020 PID_T cpid, lpid;
1021 int shmid, size, nattch;
1022 TIME_T atime, dtime, ctime;
1023 unsigned int perms;
1024 int items_read;
1025
1026 items_read = sscanf (buf,
1027 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
1028 &key, &shmid, &perms, &size,
1029 &cpid, &lpid,
1030 &nattch,
1031 &uid, &gid, &cuid, &cgid,
1032 &atime, &dtime, &ctime);
1033
1034 if (items_read == 14)
1035 {
1036 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1037 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1038 char ccmd[32], lcmd[32];
1039 char atime_str[32], dtime_str[32], ctime_str[32];
1040
1041 user_from_uid (user, sizeof (user), uid);
1042 group_from_gid (group, sizeof (group), gid);
1043 user_from_uid (cuser, sizeof (cuser), cuid);
1044 group_from_gid (cgroup, sizeof (cgroup), cgid);
1045
1046 command_from_pid (ccmd, sizeof (ccmd), cpid);
1047 command_from_pid (lcmd, sizeof (lcmd), lpid);
1048
1049 time_from_time_t (atime_str, sizeof (atime_str), atime);
1050 time_from_time_t (dtime_str, sizeof (dtime_str), dtime);
1051 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1052
1053 string_xml_appendf
1054 (buffer,
1055 "<item>"
1056 "<column name=\"key\">%d</column>"
1057 "<column name=\"shmid\">%d</column>"
1058 "<column name=\"permissions\">%o</column>"
1059 "<column name=\"size\">%d</column>"
1060 "<column name=\"creator command\">%s</column>"
1061 "<column name=\"last op. command\">%s</column>"
1062 "<column name=\"num attached\">%d</column>"
1063 "<column name=\"user\">%s</column>"
1064 "<column name=\"group\">%s</column>"
1065 "<column name=\"creator user\">%s</column>"
1066 "<column name=\"creator group\">%s</column>"
1067 "<column name=\"last shmat() time\">%s</column>"
1068 "<column name=\"last shmdt() time\">%s</column>"
1069 "<column name=\"last shmctl() time\">%s</column>"
1070 "</item>",
1071 key,
1072 shmid,
1073 perms,
1074 size,
1075 ccmd,
1076 lcmd,
1077 nattch,
1078 user,
1079 group,
1080 cuser,
1081 cgroup,
1082 atime_str,
1083 dtime_str,
1084 ctime_str);
1085 }
1086 }
1087 }
1088 while (!feof (fp.get ()));
1089 }
1090
1091 buffer += "</osdata>\n";
1092
1093 return buffer;
1094}
1095
1096/* Collect data about semaphores recorded in /proc and write it
1097 into BUFFER. */
1098
1099static std::string
1101{
1102 std::string buffer = "<osdata type=\"semaphores\">\n";
1103
1104 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1105 if (fp)
1106 {
1107 char buf[8192];
1108
1109 do
1110 {
1111 if (fgets (buf, sizeof (buf), fp.get ()))
1112 {
1113 key_t key;
1114 uid_t uid, cuid;
1115 gid_t gid, cgid;
1116 unsigned int perms, nsems;
1117 int semid;
1118 TIME_T otime, ctime;
1119 int items_read;
1120
1121 items_read = sscanf (buf,
1122 "%d %d %o %u %d %d %d %d %lld %lld",
1123 &key, &semid, &perms, &nsems,
1124 &uid, &gid, &cuid, &cgid,
1125 &otime, &ctime);
1126
1127 if (items_read == 10)
1128 {
1129 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1130 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1131 char otime_str[32], ctime_str[32];
1132
1133 user_from_uid (user, sizeof (user), uid);
1134 group_from_gid (group, sizeof (group), gid);
1135 user_from_uid (cuser, sizeof (cuser), cuid);
1136 group_from_gid (cgroup, sizeof (cgroup), cgid);
1137
1138 time_from_time_t (otime_str, sizeof (otime_str), otime);
1139 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1140
1141 string_xml_appendf
1142 (buffer,
1143 "<item>"
1144 "<column name=\"key\">%d</column>"
1145 "<column name=\"semid\">%d</column>"
1146 "<column name=\"permissions\">%o</column>"
1147 "<column name=\"num semaphores\">%u</column>"
1148 "<column name=\"user\">%s</column>"
1149 "<column name=\"group\">%s</column>"
1150 "<column name=\"creator user\">%s</column>"
1151 "<column name=\"creator group\">%s</column>"
1152 "<column name=\"last semop() time\">%s</column>"
1153 "<column name=\"last semctl() time\">%s</column>"
1154 "</item>",
1155 key,
1156 semid,
1157 perms,
1158 nsems,
1159 user,
1160 group,
1161 cuser,
1162 cgroup,
1163 otime_str,
1164 ctime_str);
1165 }
1166 }
1167 }
1168 while (!feof (fp.get ()));
1169 }
1170
1171 buffer += "</osdata>\n";
1172
1173 return buffer;
1174}
1175
1176/* Collect data about message queues recorded in /proc and write it
1177 into BUFFER. */
1178
1179static std::string
1181{
1182 std::string buffer = "<osdata type=\"message queues\">\n";
1183
1184 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1185 if (fp)
1186 {
1187 char buf[8192];
1188
1189 do
1190 {
1191 if (fgets (buf, sizeof (buf), fp.get ()))
1192 {
1193 key_t key;
1194 PID_T lspid, lrpid;
1195 uid_t uid, cuid;
1196 gid_t gid, cgid;
1197 unsigned int perms, cbytes, qnum;
1198 int msqid;
1199 TIME_T stime, rtime, ctime;
1200 int items_read;
1201
1202 items_read = sscanf (buf,
1203 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1204 &key, &msqid, &perms, &cbytes, &qnum,
1205 &lspid, &lrpid, &uid, &gid, &cuid, &cgid,
1206 &stime, &rtime, &ctime);
1207
1208 if (items_read == 14)
1209 {
1210 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1211 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1212 char lscmd[32], lrcmd[32];
1213 char stime_str[32], rtime_str[32], ctime_str[32];
1214
1215 user_from_uid (user, sizeof (user), uid);
1216 group_from_gid (group, sizeof (group), gid);
1217 user_from_uid (cuser, sizeof (cuser), cuid);
1218 group_from_gid (cgroup, sizeof (cgroup), cgid);
1219
1220 command_from_pid (lscmd, sizeof (lscmd), lspid);
1221 command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
1222
1223 time_from_time_t (stime_str, sizeof (stime_str), stime);
1224 time_from_time_t (rtime_str, sizeof (rtime_str), rtime);
1225 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1226
1227 string_xml_appendf
1228 (buffer,
1229 "<item>"
1230 "<column name=\"key\">%d</column>"
1231 "<column name=\"msqid\">%d</column>"
1232 "<column name=\"permissions\">%o</column>"
1233 "<column name=\"num used bytes\">%u</column>"
1234 "<column name=\"num messages\">%u</column>"
1235 "<column name=\"last msgsnd() command\">%s</column>"
1236 "<column name=\"last msgrcv() command\">%s</column>"
1237 "<column name=\"user\">%s</column>"
1238 "<column name=\"group\">%s</column>"
1239 "<column name=\"creator user\">%s</column>"
1240 "<column name=\"creator group\">%s</column>"
1241 "<column name=\"last msgsnd() time\">%s</column>"
1242 "<column name=\"last msgrcv() time\">%s</column>"
1243 "<column name=\"last msgctl() time\">%s</column>"
1244 "</item>",
1245 key,
1246 msqid,
1247 perms,
1248 cbytes,
1249 qnum,
1250 lscmd,
1251 lrcmd,
1252 user,
1253 group,
1254 cuser,
1255 cgroup,
1256 stime_str,
1257 rtime_str,
1258 ctime_str);
1259 }
1260 }
1261 }
1262 while (!feof (fp.get ()));
1263 }
1264
1265 buffer += "</osdata>\n";
1266
1267 return buffer;
1268}
1269
1270/* Collect data about loaded kernel modules and write it into
1271 BUFFER. */
1272
1273static std::string
1275{
1276 std::string buffer = "<osdata type=\"modules\">\n";
1277
1278 gdb_file_up fp = gdb_fopen_cloexec ("/proc/modules", "r");
1279 if (fp)
1280 {
1281 char buf[8192];
1282
1283 do
1284 {
1285 if (fgets (buf, sizeof (buf), fp.get ()))
1286 {
1287 char *name, *dependencies, *status, *tmp, *saveptr;
1288 unsigned int size;
1289 unsigned long long address;
1290 int uses;
1291
1292 name = strtok_r (buf, " ", &saveptr);
1293 if (name == NULL)
1294 continue;
1295
1296 tmp = strtok_r (NULL, " ", &saveptr);
1297 if (tmp == NULL)
1298 continue;
1299 if (sscanf (tmp, "%u", &size) != 1)
1300 continue;
1301
1302 tmp = strtok_r (NULL, " ", &saveptr);
1303 if (tmp == NULL)
1304 continue;
1305 if (sscanf (tmp, "%d", &uses) != 1)
1306 continue;
1307
1308 dependencies = strtok_r (NULL, " ", &saveptr);
1309 if (dependencies == NULL)
1310 continue;
1311
1312 status = strtok_r (NULL, " ", &saveptr);
1313 if (status == NULL)
1314 continue;
1315
1316 tmp = strtok_r (NULL, "\n", &saveptr);
1317 if (tmp == NULL)
1318 continue;
1319 if (sscanf (tmp, "%llx", &address) != 1)
1320 continue;
1321
1322 string_xml_appendf (buffer,
1323 "<item>"
1324 "<column name=\"name\">%s</column>"
1325 "<column name=\"size\">%u</column>"
1326 "<column name=\"num uses\">%d</column>"
1327 "<column name=\"dependencies\">%s</column>"
1328 "<column name=\"status\">%s</column>"
1329 "<column name=\"address\">%llx</column>"
1330 "</item>",
1331 name,
1332 size,
1333 uses,
1334 dependencies,
1335 status,
1336 address);
1337 }
1338 }
1339 while (!feof (fp.get ()));
1340 }
1341
1342 buffer += "</osdata>\n";
1343
1344 return buffer;
1345}
1346
1347static std::string linux_xfer_osdata_info_os_types ();
1348
1349static struct osdata_type {
1350 const char *type;
1351 const char *title;
1352 const char *description;
1353 std::string (*take_snapshot) ();
1354 std::string buffer;
1355} osdata_table[] = {
1356 { "types", "Types", "Listing of info os types you can list",
1358 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1360 { "files", "File descriptors", "Listing of all file descriptors",
1362 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1364 { "msg", "Message queues", "Listing of all message queues",
1366 { "processes", "Processes", "Listing of all processes",
1368 { "procgroups", "Process groups", "Listing of all process groups",
1370 { "semaphores", "Semaphores", "Listing of all semaphores",
1372 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1374 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1376 { "threads", "Threads", "Listing of all threads",
1378 { NULL, NULL, NULL }
1380
1381/* Collect data about all types info os can show in BUFFER. */
1382
1383static std::string
1385{
1386 std::string buffer = "<osdata type=\"types\">\n";
1387
1388 /* Start the below loop at 1, as we do not want to list ourselves. */
1389 for (int i = 1; osdata_table[i].type; ++i)
1390 string_xml_appendf (buffer,
1391 "<item>"
1392 "<column name=\"Type\">%s</column>"
1393 "<column name=\"Description\">%s</column>"
1394 "<column name=\"Title\">%s</column>"
1395 "</item>",
1396 osdata_table[i].type,
1397 osdata_table[i].description,
1398 osdata_table[i].title);
1399
1400 buffer += "</osdata>\n";
1401
1402 return buffer;
1403}
1404
1405
1406/* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1407 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
1408
1409static LONGEST
1411 gdb_byte *readbuf, ULONGEST offset, ULONGEST len)
1412{
1413 gdb_assert (readbuf);
1414
1415 if (offset == 0)
1416 osd->buffer = osd->take_snapshot ();
1417
1418 if (offset >= osd->buffer.size ())
1419 {
1420 /* Done. Get rid of the buffer. */
1421 osd->buffer.clear ();
1422 return 0;
1423 }
1424
1425 len = std::min (len, osd->buffer.size () - offset);
1426 memcpy (readbuf, &osd->buffer[offset], len);
1427
1428 return len;
1429
1430}
1431
1432LONGEST
1433linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
1434 ULONGEST offset, ULONGEST len)
1435{
1436 if (!annex || *annex == '\0')
1437 {
1438 return common_getter (&osdata_table[0],
1439 readbuf, offset, len);
1440 }
1441 else
1442 {
1443 int i;
1444
1445 for (i = 0; osdata_table[i].type; ++i)
1446 {
1447 if (strcmp (annex, osdata_table[i].type) == 0)
1448 return common_getter (&osdata_table[i],
1449 readbuf, offset, len);
1450 }
1451
1452 return 0;
1453 }
1454}
static const char * format_socket_state(unsigned char state)
static int get_process_owner(uid_t *owner, PID_T pid)
static int get_cores_used_by_process(PID_T pid, int *cores, const int num_cores)
static LONGEST common_getter(struct osdata_type *osd, gdb_byte *readbuf, ULONGEST offset, ULONGEST len)
#define MAX_PID_T_STRLEN
static std::string linux_xfer_osdata_cpus()
static gdb::optional< size_t > get_core_array_size_using_sys_possible()
static char * commandline_from_pid(PID_T pid)
static std::string linux_xfer_osdata_modules()
static void user_from_uid(char *user, int maxlen, uid_t uid)
#define NAMELEN(dirent)
static struct osdata_type osdata_table[]
static size_t get_core_array_size()
static std::string linux_xfer_osdata_processgroups()
static void command_from_pid(char *command, int maxlen, PID_T pid)
static void time_from_time_t(char *time, int maxlen, TIME_T seconds)
static std::string linux_xfer_osdata_sem()
LONGEST linux_common_xfer_osdata(const char *annex, gdb_byte *readbuf, ULONGEST offset, ULONGEST len)
static std::string linux_xfer_osdata_processes()
static std::string linux_xfer_osdata_threads()
static void print_sockets(unsigned short family, int tcp, std::string &buffer)
static std::string linux_xfer_osdata_msg()
int linux_common_core_of_thread(ptid_t ptid)
static void group_from_gid(char *group, int maxlen, gid_t gid)
static std::string linux_xfer_osdata_isockets()
static std::string linux_xfer_osdata_shm()
long long TIME_T
static std::string linux_xfer_osdata_fds()
static std::string linux_xfer_osdata_info_os_types()
long long PID_T
std::string buffer
const char * title
std::string(* take_snapshot)()
const char * description
const char * type
PID_T pgid
pid_pgid_entry(PID_T pid_, PID_T pgid_)
bool is_leader() const
bool operator<(const pid_pgid_entry &other) const
PID_T pid
struct sockaddr_in sin
struct sockaddr sa
struct sockaddr_in6 sin6