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