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