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