Explicitly include <array> for std::array<>.
[deliverable/binutils-gdb.git] / gdb / nat / linux-osdata.c
CommitLineData
d26e3629
KY
1/* Linux-specific functions to retrieve OS data.
2
61baf725 3 Copyright (C) 2009-2017 Free Software Foundation, Inc.
d26e3629
KY
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
727605ca 20#include "common-defs.h"
d26e3629
KY
21#include "linux-osdata.h"
22
23#include <sys/types.h>
b245bdfc 24#include <sys/sysinfo.h>
d26e3629 25#include <ctype.h>
d26e3629
KY
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 "xml-utils.h"
36#include "buffer.h"
2978b111 37#include <dirent.h>
53ce3c39 38#include <sys/stat.h>
614c279d 39#include "filestuff.h"
d26e3629 40
2978b111
TT
41#define NAMELEN(dirent) strlen ((dirent)->d_name)
42
85d4a676
SS
43/* Define PID_T to be a fixed size that is at least as large as pid_t,
44 so that reading pid values embedded in /proc works
45 consistently. */
46
47typedef long long PID_T;
48
49/* Define TIME_T to be at least as large as time_t, so that reading
50 time values embedded in /proc works consistently. */
51
52typedef long long TIME_T;
53
54#define MAX_PID_T_STRLEN (sizeof ("-9223372036854775808") - 1)
55
56/* Returns the CPU core that thread PTID is currently running on. */
57
2e794194
JK
58/* Compute and return the processor core of a given thread. */
59
d26e3629
KY
60int
61linux_common_core_of_thread (ptid_t ptid)
62{
85d4a676 63 char filename[sizeof ("/proc//task//stat") + 2 * MAX_PID_T_STRLEN];
d26e3629
KY
64 char *content = NULL;
65 char *p;
66 char *ts = 0;
67 int content_read = 0;
68 int i;
69 int core;
70
85d4a676
SS
71 sprintf (filename, "/proc/%lld/task/%lld/stat",
72 (PID_T) ptid_get_pid (ptid), (PID_T) ptid_get_lwp (ptid));
d419f42d 73 gdb_file_up f = gdb_fopen_cloexec (filename, "r");
d26e3629
KY
74 if (!f)
75 return -1;
76
77 for (;;)
78 {
79 int n;
224c3ddb 80 content = (char *) xrealloc (content, content_read + 1024);
d419f42d 81 n = fread (content + content_read, 1, 1024, f.get ());
d26e3629
KY
82 content_read += n;
83 if (n < 1024)
84 {
85 content[content_read] = '\0';
86 break;
87 }
88 }
89
184cd072
JK
90 /* ps command also relies on no trailing fields ever contain ')'. */
91 p = strrchr (content, ')');
d26e3629
KY
92 if (p != NULL)
93 p++;
94
95 /* If the first field after program name has index 0, then core number is
96 the field with index 36. There's no constant for that anywhere. */
97 if (p != NULL)
98 p = strtok_r (p, " ", &ts);
99 for (i = 0; p != NULL && i != 36; ++i)
100 p = strtok_r (NULL, " ", &ts);
101
102 if (p == NULL || sscanf (p, "%d", &core) == 0)
103 core = -1;
104
105 xfree (content);
d26e3629
KY
106
107 return core;
108}
109
85d4a676
SS
110/* Finds the command-line of process PID and copies it into COMMAND.
111 At most MAXLEN characters are copied. If the command-line cannot
112 be found, PID is copied into command in text-form. */
113
d26e3629 114static void
85d4a676 115command_from_pid (char *command, int maxlen, PID_T pid)
d26e3629 116{
85d4a676 117 char *stat_path = xstrprintf ("/proc/%lld/stat", pid);
d419f42d 118 gdb_file_up fp = gdb_fopen_cloexec (stat_path, "r");
d26e3629
KY
119
120 command[0] = '\0';
121
122 if (fp)
123 {
124 /* sizeof (cmd) should be greater or equal to TASK_COMM_LEN (in
125 include/linux/sched.h in the Linux kernel sources) plus two
126 (for the brackets). */
f60db4f0 127 char cmd[18];
85d4a676 128 PID_T stat_pid;
d419f42d 129 int items_read = fscanf (fp.get (), "%lld %17s", &stat_pid, cmd);
d26e3629
KY
130
131 if (items_read == 2 && pid == stat_pid)
132 {
133 cmd[strlen (cmd) - 1] = '\0'; /* Remove trailing parenthesis. */
134 strncpy (command, cmd + 1, maxlen); /* Ignore leading parenthesis. */
135 }
d26e3629
KY
136 }
137 else
138 {
139 /* Return the PID if a /proc entry for the process cannot be found. */
85d4a676 140 snprintf (command, maxlen, "%lld", pid);
d26e3629
KY
141 }
142
143 command[maxlen - 1] = '\0'; /* Ensure string is null-terminated. */
144
145 xfree (stat_path);
146}
147
85d4a676
SS
148/* Returns the command-line of the process with the given PID. The
149 returned string needs to be freed using xfree after use. */
d26e3629
KY
150
151static char *
85d4a676 152commandline_from_pid (PID_T pid)
d26e3629 153{
85d4a676 154 char *pathname = xstrprintf ("/proc/%lld/cmdline", pid);
d26e3629 155 char *commandline = NULL;
d419f42d 156 gdb_file_up f = gdb_fopen_cloexec (pathname, "r");
d26e3629
KY
157
158 if (f)
159 {
160 size_t len = 0;
161
d419f42d 162 while (!feof (f.get ()))
d26e3629
KY
163 {
164 char buf[1024];
d419f42d 165 size_t read_bytes = fread (buf, 1, sizeof (buf), f.get ());
d26e3629
KY
166
167 if (read_bytes)
168 {
169 commandline = (char *) xrealloc (commandline, len + read_bytes + 1);
170 memcpy (commandline + len, buf, read_bytes);
171 len += read_bytes;
172 }
173 }
174
d26e3629
KY
175 if (commandline)
176 {
177 size_t i;
178
179 /* Replace null characters with spaces. */
180 for (i = 0; i < len; ++i)
181 if (commandline[i] == '\0')
182 commandline[i] = ' ';
183
184 commandline[len] = '\0';
185 }
186 else
187 {
85d4a676
SS
188 /* Return the command in square brackets if the command-line
189 is empty. */
d26e3629
KY
190 commandline = (char *) xmalloc (32);
191 commandline[0] = '[';
192 command_from_pid (commandline + 1, 31, pid);
193
194 len = strlen (commandline);
195 if (len < 31)
196 strcat (commandline, "]");
197 }
198 }
199
200 xfree (pathname);
201
202 return commandline;
203}
204
85d4a676
SS
205/* Finds the user name for the user UID and copies it into USER. At
206 most MAXLEN characters are copied. */
207
d26e3629
KY
208static void
209user_from_uid (char *user, int maxlen, uid_t uid)
210{
211 struct passwd *pwentry = getpwuid (uid);
212
213 if (pwentry)
214 {
215 strncpy (user, pwentry->pw_name, maxlen);
85d4a676
SS
216 /* Ensure that the user name is null-terminated. */
217 user[maxlen - 1] = '\0';
d26e3629
KY
218 }
219 else
220 user[0] = '\0';
221}
222
85d4a676
SS
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
d26e3629 226static int
85d4a676 227get_process_owner (uid_t *owner, PID_T pid)
d26e3629
KY
228{
229 struct stat statbuf;
85d4a676 230 char procentry[sizeof ("/proc/") + MAX_PID_T_STRLEN];
d26e3629 231
85d4a676 232 sprintf (procentry, "/proc/%lld", pid);
d26e3629
KY
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
85d4a676 243/* Find the CPU cores used by process PID and return them in CORES.
184cd072 244 CORES points to an array of NUM_CORES elements. */
d26e3629
KY
245
246static int
184cd072 247get_cores_used_by_process (PID_T pid, int *cores, const int num_cores)
d26e3629 248{
85d4a676 249 char taskdir[sizeof ("/proc/") + MAX_PID_T_STRLEN + sizeof ("/task") - 1];
d26e3629
KY
250 DIR *dir;
251 struct dirent *dp;
252 int task_count = 0;
253
85d4a676 254 sprintf (taskdir, "/proc/%lld/task", pid);
d26e3629 255 dir = opendir (taskdir);
e5798bef 256 if (dir)
d26e3629 257 {
e5798bef
PA
258 while ((dp = readdir (dir)) != NULL)
259 {
85d4a676 260 PID_T tid;
e5798bef 261 int core;
d26e3629 262
e5798bef 263 if (!isdigit (dp->d_name[0])
85d4a676 264 || NAMELEN (dp) > MAX_PID_T_STRLEN)
e5798bef 265 continue;
d26e3629 266
85d4a676
SS
267 sscanf (dp->d_name, "%lld", &tid);
268 core = linux_common_core_of_thread (ptid_build ((pid_t) pid,
269 (pid_t) tid, 0));
d26e3629 270
184cd072 271 if (core >= 0 && core < num_cores)
e5798bef
PA
272 {
273 ++cores[core];
274 ++task_count;
275 }
d26e3629 276 }
d26e3629 277
e5798bef
PA
278 closedir (dir);
279 }
d26e3629
KY
280
281 return task_count;
282}
283
284static LONGEST
285linux_xfer_osdata_processes (gdb_byte *readbuf,
dea80a27 286 ULONGEST offset, ULONGEST len)
d26e3629
KY
287{
288 /* We make the process list snapshot when the object starts to be read. */
289 static const char *buf;
290 static LONGEST len_avail = -1;
291 static struct buffer buffer;
292
293 if (offset == 0)
294 {
295 DIR *dirp;
296
297 if (len_avail != -1 && len_avail != 0)
298 buffer_free (&buffer);
299 len_avail = 0;
300 buf = NULL;
301 buffer_init (&buffer);
302 buffer_grow_str (&buffer, "<osdata type=\"processes\">\n");
303
304 dirp = opendir ("/proc");
305 if (dirp)
306 {
b245bdfc 307 const int num_cores = sysconf (_SC_NPROCESSORS_ONLN);
d26e3629
KY
308 struct dirent *dp;
309
310 while ((dp = readdir (dirp)) != NULL)
311 {
85d4a676 312 PID_T pid;
d26e3629
KY
313 uid_t owner;
314 char user[UT_NAMESIZE];
315 char *command_line;
316 int *cores;
317 int task_count;
318 char *cores_str;
319 int i;
320
321 if (!isdigit (dp->d_name[0])
85d4a676 322 || NAMELEN (dp) > MAX_PID_T_STRLEN)
d26e3629
KY
323 continue;
324
85d4a676 325 sscanf (dp->d_name, "%lld", &pid);
d26e3629
KY
326 command_line = commandline_from_pid (pid);
327
328 if (get_process_owner (&owner, pid) == 0)
329 user_from_uid (user, sizeof (user), owner);
330 else
331 strcpy (user, "?");
332
333 /* Find CPU cores used by the process. */
8d749320 334 cores = XCNEWVEC (int, num_cores);
184cd072 335 task_count = get_cores_used_by_process (pid, cores, num_cores);
d26e3629
KY
336 cores_str = (char *) xcalloc (task_count, sizeof ("4294967295") + 1);
337
338 for (i = 0; i < num_cores && task_count > 0; ++i)
339 if (cores[i])
340 {
85d4a676 341 char core_str[sizeof ("4294967295")];
d26e3629
KY
342
343 sprintf (core_str, "%d", i);
344 strcat (cores_str, core_str);
345
346 task_count -= cores[i];
347 if (task_count > 0)
348 strcat (cores_str, ",");
349 }
350
351 xfree (cores);
352
353 buffer_xml_printf (
354 &buffer,
355 "<item>"
85d4a676 356 "<column name=\"pid\">%lld</column>"
d26e3629
KY
357 "<column name=\"user\">%s</column>"
358 "<column name=\"command\">%s</column>"
359 "<column name=\"cores\">%s</column>"
360 "</item>",
361 pid,
362 user,
363 command_line ? command_line : "",
364 cores_str);
365
366 xfree (command_line);
367 xfree (cores_str);
368 }
369
370 closedir (dirp);
371 }
372
373 buffer_grow_str0 (&buffer, "</osdata>\n");
374 buf = buffer_finish (&buffer);
375 len_avail = strlen (buf);
376 }
377
378 if (offset >= len_avail)
379 {
380 /* Done. Get rid of the buffer. */
381 buffer_free (&buffer);
382 buf = NULL;
383 len_avail = 0;
384 return 0;
385 }
386
387 if (len > len_avail - offset)
388 len = len_avail - offset;
389 memcpy (readbuf, buf + offset, len);
390
391 return len;
392}
393
85d4a676
SS
394/* Auxiliary function used by qsort to sort processes by process
395 group. Compares two processes with ids PROCESS1 and PROCESS2.
396 PROCESS1 comes before PROCESS2 if it has a lower process group id.
397 If they belong to the same process group, PROCESS1 comes before
398 PROCESS2 if it has a lower process id or is the process group
399 leader. */
400
401static int
402compare_processes (const void *process1, const void *process2)
403{
404 PID_T pid1 = *((PID_T *) process1);
405 PID_T pid2 = *((PID_T *) process2);
406 PID_T pgid1 = *((PID_T *) process1 + 1);
407 PID_T pgid2 = *((PID_T *) process2 + 1);
408
409 /* Sort by PGID. */
410 if (pgid1 < pgid2)
411 return -1;
412 else if (pgid1 > pgid2)
413 return 1;
414 else
415 {
416 /* Process group leaders always come first, else sort by PID. */
417 if (pid1 == pgid1)
418 return -1;
419 else if (pid2 == pgid2)
420 return 1;
421 else if (pid1 < pid2)
422 return -1;
423 else if (pid1 > pid2)
424 return 1;
425 else
426 return 0;
427 }
428}
429
430/* Collect all process groups from /proc. */
431
432static LONGEST
433linux_xfer_osdata_processgroups (gdb_byte *readbuf,
dea80a27 434 ULONGEST offset, ULONGEST len)
85d4a676
SS
435{
436 /* We make the process list snapshot when the object starts to be read. */
437 static const char *buf;
438 static LONGEST len_avail = -1;
439 static struct buffer buffer;
440
441 if (offset == 0)
442 {
443 DIR *dirp;
444
445 if (len_avail != -1 && len_avail != 0)
446 buffer_free (&buffer);
447 len_avail = 0;
448 buf = NULL;
449 buffer_init (&buffer);
450 buffer_grow_str (&buffer, "<osdata type=\"process groups\">\n");
451
452 dirp = opendir ("/proc");
453 if (dirp)
454 {
455 struct dirent *dp;
456 const size_t list_block_size = 512;
8d749320 457 PID_T *process_list = XNEWVEC (PID_T, list_block_size * 2);
85d4a676
SS
458 size_t process_count = 0;
459 size_t i;
460
461 /* Build list consisting of PIDs followed by their
462 associated PGID. */
463 while ((dp = readdir (dirp)) != NULL)
464 {
465 PID_T pid, pgid;
466
467 if (!isdigit (dp->d_name[0])
468 || NAMELEN (dp) > MAX_PID_T_STRLEN)
469 continue;
470
471 sscanf (dp->d_name, "%lld", &pid);
472 pgid = getpgid (pid);
473
474 if (pgid > 0)
475 {
476 process_list[2 * process_count] = pid;
477 process_list[2 * process_count + 1] = pgid;
478 ++process_count;
479
480 /* Increase the size of the list if necessary. */
481 if (process_count % list_block_size == 0)
482 process_list = (PID_T *) xrealloc (
483 process_list,
484 (process_count + list_block_size)
485 * 2 * sizeof (PID_T));
486 }
487 }
488
489 closedir (dirp);
490
491 /* Sort the process list. */
492 qsort (process_list, process_count, 2 * sizeof (PID_T),
493 compare_processes);
494
495 for (i = 0; i < process_count; ++i)
496 {
497 PID_T pid = process_list[2 * i];
498 PID_T pgid = process_list[2 * i + 1];
499 char leader_command[32];
500 char *command_line;
501
502 command_from_pid (leader_command, sizeof (leader_command), pgid);
503 command_line = commandline_from_pid (pid);
504
505 buffer_xml_printf (
506 &buffer,
507 "<item>"
508 "<column name=\"pgid\">%lld</column>"
509 "<column name=\"leader command\">%s</column>"
510 "<column name=\"pid\">%lld</column>"
511 "<column name=\"command line\">%s</column>"
512 "</item>",
513 pgid,
514 leader_command,
515 pid,
516 command_line ? command_line : "");
517
518 xfree (command_line);
519 }
520
521 xfree (process_list);
522 }
523
524 buffer_grow_str0 (&buffer, "</osdata>\n");
525 buf = buffer_finish (&buffer);
526 len_avail = strlen (buf);
527 }
528
529 if (offset >= len_avail)
530 {
531 /* Done. Get rid of the buffer. */
532 buffer_free (&buffer);
533 buf = NULL;
534 len_avail = 0;
535 return 0;
536 }
537
538 if (len > len_avail - offset)
539 len = len_avail - offset;
540 memcpy (readbuf, buf + offset, len);
541
542 return len;
543}
544
545/* Collect all the threads in /proc by iterating through processes and
546 then tasks within each process. */
547
d26e3629
KY
548static LONGEST
549linux_xfer_osdata_threads (gdb_byte *readbuf,
dea80a27 550 ULONGEST offset, ULONGEST len)
d26e3629
KY
551{
552 /* We make the process list snapshot when the object starts to be read. */
553 static const char *buf;
554 static LONGEST len_avail = -1;
555 static struct buffer buffer;
556
557 if (offset == 0)
558 {
559 DIR *dirp;
560
561 if (len_avail != -1 && len_avail != 0)
562 buffer_free (&buffer);
563 len_avail = 0;
564 buf = NULL;
565 buffer_init (&buffer);
566 buffer_grow_str (&buffer, "<osdata type=\"threads\">\n");
567
568 dirp = opendir ("/proc");
569 if (dirp)
570 {
571 struct dirent *dp;
572
573 while ((dp = readdir (dirp)) != NULL)
574 {
575 struct stat statbuf;
576 char procentry[sizeof ("/proc/4294967295")];
577
578 if (!isdigit (dp->d_name[0])
579 || NAMELEN (dp) > sizeof ("4294967295") - 1)
580 continue;
581
97e64e5a
YQ
582 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
583 dp->d_name);
d26e3629
KY
584 if (stat (procentry, &statbuf) == 0
585 && S_ISDIR (statbuf.st_mode))
586 {
587 DIR *dirp2;
588 char *pathname;
85d4a676 589 PID_T pid;
d26e3629
KY
590 char command[32];
591
592 pathname = xstrprintf ("/proc/%s/task", dp->d_name);
593
594 pid = atoi (dp->d_name);
595 command_from_pid (command, sizeof (command), pid);
596
597 dirp2 = opendir (pathname);
598
599 if (dirp2)
600 {
601 struct dirent *dp2;
602
603 while ((dp2 = readdir (dirp2)) != NULL)
604 {
85d4a676 605 PID_T tid;
d26e3629
KY
606 int core;
607
608 if (!isdigit (dp2->d_name[0])
609 || NAMELEN (dp2) > sizeof ("4294967295") - 1)
610 continue;
611
612 tid = atoi (dp2->d_name);
613 core = linux_common_core_of_thread (ptid_build (pid, tid, 0));
614
615 buffer_xml_printf (
616 &buffer,
617 "<item>"
85d4a676 618 "<column name=\"pid\">%lld</column>"
d26e3629 619 "<column name=\"command\">%s</column>"
85d4a676 620 "<column name=\"tid\">%lld</column>"
d26e3629
KY
621 "<column name=\"core\">%d</column>"
622 "</item>",
623 pid,
624 command,
625 tid,
626 core);
627 }
628
629 closedir (dirp2);
630 }
631
632 xfree (pathname);
633 }
634 }
635
636 closedir (dirp);
637 }
638
639 buffer_grow_str0 (&buffer, "</osdata>\n");
640 buf = buffer_finish (&buffer);
641 len_avail = strlen (buf);
642 }
643
644 if (offset >= len_avail)
645 {
646 /* Done. Get rid of the buffer. */
647 buffer_free (&buffer);
648 buf = NULL;
649 len_avail = 0;
650 return 0;
651 }
652
653 if (len > len_avail - offset)
654 len = len_avail - offset;
655 memcpy (readbuf, buf + offset, len);
656
657 return len;
658}
659
d33279b3
AT
660/* Collect data about the cpus/cores on the system */
661
662static LONGEST
663linux_xfer_osdata_cpus (gdb_byte *readbuf,
664 ULONGEST offset, ULONGEST len)
665{
666 static const char *buf;
667 static LONGEST len_avail = -1;
668 static struct buffer buffer;
669
670 if (offset == 0)
671 {
d33279b3
AT
672 int first_item = 1;
673
674 if (len_avail != -1 && len_avail != 0)
675 buffer_free (&buffer);
676 len_avail = 0;
677 buf = NULL;
678 buffer_init (&buffer);
679 buffer_grow_str (&buffer, "<osdata type=\"cpus\">\n");
680
d419f42d 681 gdb_file_up fp = gdb_fopen_cloexec ("/proc/cpuinfo", "r");
d33279b3
AT
682 if (fp != NULL)
683 {
684 char buf[8192];
685
686 do
687 {
d419f42d 688 if (fgets (buf, sizeof (buf), fp.get ()))
d33279b3
AT
689 {
690 char *key, *value;
691 int i = 0;
692
693 key = strtok (buf, ":");
694 if (key == NULL)
695 continue;
696
697 value = strtok (NULL, ":");
698 if (value == NULL)
699 continue;
700
701 while (key[i] != '\t' && key[i] != '\0')
702 i++;
703
704 key[i] = '\0';
705
706 i = 0;
707 while (value[i] != '\t' && value[i] != '\0')
708 i++;
709
710 value[i] = '\0';
711
712 if (strcmp (key, "processor") == 0)
713 {
714 if (first_item)
715 buffer_grow_str (&buffer, "<item>");
716 else
717 buffer_grow_str (&buffer, "</item><item>");
718
719 first_item = 0;
720 }
721
722 buffer_xml_printf (&buffer,
723 "<column name=\"%s\">%s</column>",
724 key,
725 value);
726 }
727 }
d419f42d 728 while (!feof (fp.get ()));
d33279b3
AT
729
730 if (first_item == 0)
731 buffer_grow_str (&buffer, "</item>");
d33279b3
AT
732 }
733
734 buffer_grow_str0 (&buffer, "</osdata>\n");
735 buf = buffer_finish (&buffer);
736 len_avail = strlen (buf);
737 }
738
739 if (offset >= len_avail)
740 {
741 /* Done. Get rid of the buffer. */
742 buffer_free (&buffer);
743 buf = NULL;
744 len_avail = 0;
745 return 0;
746 }
747
748 if (len > len_avail - offset)
749 len = len_avail - offset;
750 memcpy (readbuf, buf + offset, len);
751
752 return len;
753}
754
85d4a676
SS
755/* Collect all the open file descriptors found in /proc and put the details
756 found about them into READBUF. */
757
758static LONGEST
759linux_xfer_osdata_fds (gdb_byte *readbuf,
dea80a27 760 ULONGEST offset, ULONGEST len)
85d4a676
SS
761{
762 /* We make the process list snapshot when the object starts to be read. */
763 static const char *buf;
764 static LONGEST len_avail = -1;
765 static struct buffer buffer;
766
767 if (offset == 0)
768 {
769 DIR *dirp;
770
771 if (len_avail != -1 && len_avail != 0)
772 buffer_free (&buffer);
773 len_avail = 0;
774 buf = NULL;
775 buffer_init (&buffer);
776 buffer_grow_str (&buffer, "<osdata type=\"files\">\n");
777
778 dirp = opendir ("/proc");
779 if (dirp)
780 {
781 struct dirent *dp;
782
783 while ((dp = readdir (dirp)) != NULL)
784 {
785 struct stat statbuf;
786 char procentry[sizeof ("/proc/4294967295")];
787
788 if (!isdigit (dp->d_name[0])
789 || NAMELEN (dp) > sizeof ("4294967295") - 1)
790 continue;
791
97e64e5a
YQ
792 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
793 dp->d_name);
85d4a676
SS
794 if (stat (procentry, &statbuf) == 0
795 && S_ISDIR (statbuf.st_mode))
796 {
797 char *pathname;
798 DIR *dirp2;
799 PID_T pid;
800 char command[32];
801
802 pid = atoi (dp->d_name);
803 command_from_pid (command, sizeof (command), pid);
804
805 pathname = xstrprintf ("/proc/%s/fd", dp->d_name);
806 dirp2 = opendir (pathname);
807
808 if (dirp2)
809 {
810 struct dirent *dp2;
811
812 while ((dp2 = readdir (dirp2)) != NULL)
813 {
814 char *fdname;
815 char buf[1000];
816 ssize_t rslt;
817
818 if (!isdigit (dp2->d_name[0]))
819 continue;
820
821 fdname = xstrprintf ("%s/%s", pathname, dp2->d_name);
0270a750 822 rslt = readlink (fdname, buf, sizeof (buf) - 1);
85d4a676
SS
823 if (rslt >= 0)
824 buf[rslt] = '\0';
825
826 buffer_xml_printf (
827 &buffer,
828 "<item>"
829 "<column name=\"pid\">%s</column>"
830 "<column name=\"command\">%s</column>"
831 "<column name=\"file descriptor\">%s</column>"
832 "<column name=\"name\">%s</column>"
833 "</item>",
834 dp->d_name,
835 command,
836 dp2->d_name,
837 (rslt >= 0 ? buf : dp2->d_name));
838 }
839
840 closedir (dirp2);
841 }
842
843 xfree (pathname);
844 }
845 }
846
847 closedir (dirp);
848 }
849
850 buffer_grow_str0 (&buffer, "</osdata>\n");
851 buf = buffer_finish (&buffer);
852 len_avail = strlen (buf);
853 }
854
855 if (offset >= len_avail)
856 {
857 /* Done. Get rid of the buffer. */
858 buffer_free (&buffer);
859 buf = NULL;
860 len_avail = 0;
861 return 0;
862 }
863
864 if (len > len_avail - offset)
865 len = len_avail - offset;
866 memcpy (readbuf, buf + offset, len);
867
868 return len;
869}
870
871/* Returns the socket state STATE in textual form. */
872
873static const char *
874format_socket_state (unsigned char state)
875{
876 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
877 enum {
878 TCP_ESTABLISHED = 1,
879 TCP_SYN_SENT,
880 TCP_SYN_RECV,
881 TCP_FIN_WAIT1,
882 TCP_FIN_WAIT2,
883 TCP_TIME_WAIT,
884 TCP_CLOSE,
885 TCP_CLOSE_WAIT,
886 TCP_LAST_ACK,
887 TCP_LISTEN,
888 TCP_CLOSING
889 };
890
891 switch (state)
892 {
893 case TCP_ESTABLISHED:
894 return "ESTABLISHED";
895 case TCP_SYN_SENT:
896 return "SYN_SENT";
897 case TCP_SYN_RECV:
898 return "SYN_RECV";
899 case TCP_FIN_WAIT1:
900 return "FIN_WAIT1";
901 case TCP_FIN_WAIT2:
902 return "FIN_WAIT2";
903 case TCP_TIME_WAIT:
904 return "TIME_WAIT";
905 case TCP_CLOSE:
906 return "CLOSE";
907 case TCP_CLOSE_WAIT:
908 return "CLOSE_WAIT";
909 case TCP_LAST_ACK:
910 return "LAST_ACK";
911 case TCP_LISTEN:
912 return "LISTEN";
913 case TCP_CLOSING:
914 return "CLOSING";
915 default:
916 return "(unknown)";
917 }
918}
919
920union socket_addr
921 {
922 struct sockaddr sa;
923 struct sockaddr_in sin;
924 struct sockaddr_in6 sin6;
925 };
926
927/* Auxiliary function used by linux_xfer_osdata_isocket. Formats
928 information for all open internet sockets of type FAMILY on the
929 system into BUFFER. If TCP is set, only TCP sockets are processed,
930 otherwise only UDP sockets are processed. */
931
932static void
933print_sockets (unsigned short family, int tcp, struct buffer *buffer)
934{
935 const char *proc_file;
85d4a676
SS
936
937 if (family == AF_INET)
938 proc_file = tcp ? "/proc/net/tcp" : "/proc/net/udp";
939 else if (family == AF_INET6)
940 proc_file = tcp ? "/proc/net/tcp6" : "/proc/net/udp6";
941 else
942 return;
943
d419f42d 944 gdb_file_up fp = gdb_fopen_cloexec (proc_file, "r");
85d4a676
SS
945 if (fp)
946 {
947 char buf[8192];
948
949 do
950 {
d419f42d 951 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676
SS
952 {
953 uid_t uid;
85d4a676 954 unsigned int local_port, remote_port, state;
85d4a676 955 char local_address[NI_MAXHOST], remote_address[NI_MAXHOST];
85d4a676
SS
956 int result;
957
f60db4f0
GB
958#if NI_MAXHOST <= 32
959#error "local_address and remote_address buffers too small"
960#endif
961
85d4a676 962 result = sscanf (buf,
f60db4f0 963 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
85d4a676
SS
964 local_address, &local_port,
965 remote_address, &remote_port,
966 &state,
f60db4f0 967 &uid);
85d4a676 968
f60db4f0 969 if (result == 6)
85d4a676
SS
970 {
971 union socket_addr locaddr, remaddr;
972 size_t addr_size;
973 char user[UT_NAMESIZE];
974 char local_service[NI_MAXSERV], remote_service[NI_MAXSERV];
975
976 if (family == AF_INET)
977 {
978 sscanf (local_address, "%X",
979 &locaddr.sin.sin_addr.s_addr);
980 sscanf (remote_address, "%X",
981 &remaddr.sin.sin_addr.s_addr);
982
983 locaddr.sin.sin_port = htons (local_port);
984 remaddr.sin.sin_port = htons (remote_port);
985
986 addr_size = sizeof (struct sockaddr_in);
987 }
988 else
989 {
990 sscanf (local_address, "%8X%8X%8X%8X",
991 locaddr.sin6.sin6_addr.s6_addr32,
992 locaddr.sin6.sin6_addr.s6_addr32 + 1,
993 locaddr.sin6.sin6_addr.s6_addr32 + 2,
994 locaddr.sin6.sin6_addr.s6_addr32 + 3);
995 sscanf (remote_address, "%8X%8X%8X%8X",
996 remaddr.sin6.sin6_addr.s6_addr32,
997 remaddr.sin6.sin6_addr.s6_addr32 + 1,
998 remaddr.sin6.sin6_addr.s6_addr32 + 2,
999 remaddr.sin6.sin6_addr.s6_addr32 + 3);
1000
1001 locaddr.sin6.sin6_port = htons (local_port);
1002 remaddr.sin6.sin6_port = htons (remote_port);
1003
1004 locaddr.sin6.sin6_flowinfo = 0;
1005 remaddr.sin6.sin6_flowinfo = 0;
1006 locaddr.sin6.sin6_scope_id = 0;
1007 remaddr.sin6.sin6_scope_id = 0;
1008
1009 addr_size = sizeof (struct sockaddr_in6);
1010 }
1011
1012 locaddr.sa.sa_family = remaddr.sa.sa_family = family;
1013
1014 result = getnameinfo (&locaddr.sa, addr_size,
1015 local_address, sizeof (local_address),
1016 local_service, sizeof (local_service),
1017 NI_NUMERICHOST | NI_NUMERICSERV
1018 | (tcp ? 0 : NI_DGRAM));
1019 if (result)
1020 continue;
1021
1022 result = getnameinfo (&remaddr.sa, addr_size,
1023 remote_address,
1024 sizeof (remote_address),
1025 remote_service,
1026 sizeof (remote_service),
1027 NI_NUMERICHOST | NI_NUMERICSERV
1028 | (tcp ? 0 : NI_DGRAM));
1029 if (result)
1030 continue;
1031
1032 user_from_uid (user, sizeof (user), uid);
1033
1034 buffer_xml_printf (
1035 buffer,
1036 "<item>"
1037 "<column name=\"local address\">%s</column>"
1038 "<column name=\"local port\">%s</column>"
1039 "<column name=\"remote address\">%s</column>"
1040 "<column name=\"remote port\">%s</column>"
1041 "<column name=\"state\">%s</column>"
1042 "<column name=\"user\">%s</column>"
1043 "<column name=\"family\">%s</column>"
1044 "<column name=\"protocol\">%s</column>"
1045 "</item>",
1046 local_address,
1047 local_service,
1048 remote_address,
1049 remote_service,
1050 format_socket_state (state),
1051 user,
1052 (family == AF_INET) ? "INET" : "INET6",
1053 tcp ? "STREAM" : "DGRAM");
1054 }
1055 }
1056 }
d419f42d 1057 while (!feof (fp.get ()));
85d4a676
SS
1058 }
1059}
1060
1061/* Collect data about internet sockets and write it into READBUF. */
1062
1063static LONGEST
1064linux_xfer_osdata_isockets (gdb_byte *readbuf,
dea80a27 1065 ULONGEST offset, ULONGEST len)
85d4a676
SS
1066{
1067 static const char *buf;
1068 static LONGEST len_avail = -1;
1069 static struct buffer buffer;
1070
1071 if (offset == 0)
1072 {
1073 if (len_avail != -1 && len_avail != 0)
1074 buffer_free (&buffer);
1075 len_avail = 0;
1076 buf = NULL;
1077 buffer_init (&buffer);
1078 buffer_grow_str (&buffer, "<osdata type=\"I sockets\">\n");
1079
1080 print_sockets (AF_INET, 1, &buffer);
1081 print_sockets (AF_INET, 0, &buffer);
1082 print_sockets (AF_INET6, 1, &buffer);
1083 print_sockets (AF_INET6, 0, &buffer);
1084
1085 buffer_grow_str0 (&buffer, "</osdata>\n");
1086 buf = buffer_finish (&buffer);
1087 len_avail = strlen (buf);
1088 }
1089
1090 if (offset >= len_avail)
1091 {
1092 /* Done. Get rid of the buffer. */
1093 buffer_free (&buffer);
1094 buf = NULL;
1095 len_avail = 0;
1096 return 0;
1097 }
1098
1099 if (len > len_avail - offset)
1100 len = len_avail - offset;
1101 memcpy (readbuf, buf + offset, len);
1102
1103 return len;
1104}
1105
1106/* Converts the time SECONDS into textual form and copies it into a
1107 buffer TIME, with at most MAXLEN characters copied. */
1108
1109static void
1110time_from_time_t (char *time, int maxlen, TIME_T seconds)
1111{
1112 if (!seconds)
1113 time[0] = '\0';
1114 else
1115 {
1116 time_t t = (time_t) seconds;
1117
1118 strncpy (time, ctime (&t), maxlen);
1119 time[maxlen - 1] = '\0';
1120 }
1121}
1122
1123/* Finds the group name for the group GID and copies it into GROUP.
1124 At most MAXLEN characters are copied. */
1125
1126static void
1127group_from_gid (char *group, int maxlen, gid_t gid)
1128{
1129 struct group *grentry = getgrgid (gid);
1130
1131 if (grentry)
1132 {
1133 strncpy (group, grentry->gr_name, maxlen);
1134 /* Ensure that the group name is null-terminated. */
1135 group[maxlen - 1] = '\0';
1136 }
1137 else
1138 group[0] = '\0';
1139}
1140
1141/* Collect data about shared memory recorded in /proc and write it
1142 into READBUF. */
1143
1144static LONGEST
1145linux_xfer_osdata_shm (gdb_byte *readbuf,
dea80a27 1146 ULONGEST offset, ULONGEST len)
85d4a676
SS
1147{
1148 static const char *buf;
1149 static LONGEST len_avail = -1;
1150 static struct buffer buffer;
1151
1152 if (offset == 0)
1153 {
85d4a676
SS
1154 if (len_avail != -1 && len_avail != 0)
1155 buffer_free (&buffer);
1156 len_avail = 0;
1157 buf = NULL;
1158 buffer_init (&buffer);
1159 buffer_grow_str (&buffer, "<osdata type=\"shared memory\">\n");
1160
d419f42d 1161 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
85d4a676
SS
1162 if (fp)
1163 {
1164 char buf[8192];
1165
1166 do
1167 {
d419f42d 1168 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676
SS
1169 {
1170 key_t key;
1171 uid_t uid, cuid;
1172 gid_t gid, cgid;
1173 PID_T cpid, lpid;
1174 int shmid, size, nattch;
1175 TIME_T atime, dtime, ctime;
1176 unsigned int perms;
1177 int items_read;
1178
1179 items_read = sscanf (buf,
1180 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
1181 &key, &shmid, &perms, &size,
1182 &cpid, &lpid,
1183 &nattch,
1184 &uid, &gid, &cuid, &cgid,
1185 &atime, &dtime, &ctime);
1186
1187 if (items_read == 14)
1188 {
1189 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1190 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1191 char ccmd[32], lcmd[32];
1192 char atime_str[32], dtime_str[32], ctime_str[32];
1193
1194 user_from_uid (user, sizeof (user), uid);
1195 group_from_gid (group, sizeof (group), gid);
1196 user_from_uid (cuser, sizeof (cuser), cuid);
1197 group_from_gid (cgroup, sizeof (cgroup), cgid);
1198
1199 command_from_pid (ccmd, sizeof (ccmd), cpid);
1200 command_from_pid (lcmd, sizeof (lcmd), lpid);
1201
1202 time_from_time_t (atime_str, sizeof (atime_str), atime);
1203 time_from_time_t (dtime_str, sizeof (dtime_str), dtime);
1204 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1205
1206 buffer_xml_printf (
1207 &buffer,
1208 "<item>"
1209 "<column name=\"key\">%d</column>"
1210 "<column name=\"shmid\">%d</column>"
1211 "<column name=\"permissions\">%o</column>"
1212 "<column name=\"size\">%d</column>"
1213 "<column name=\"creator command\">%s</column>"
1214 "<column name=\"last op. command\">%s</column>"
1215 "<column name=\"num attached\">%d</column>"
1216 "<column name=\"user\">%s</column>"
1217 "<column name=\"group\">%s</column>"
1218 "<column name=\"creator user\">%s</column>"
1219 "<column name=\"creator group\">%s</column>"
1220 "<column name=\"last shmat() time\">%s</column>"
1221 "<column name=\"last shmdt() time\">%s</column>"
1222 "<column name=\"last shmctl() time\">%s</column>"
1223 "</item>",
1224 key,
1225 shmid,
1226 perms,
1227 size,
1228 ccmd,
1229 lcmd,
1230 nattch,
1231 user,
1232 group,
1233 cuser,
1234 cgroup,
1235 atime_str,
1236 dtime_str,
1237 ctime_str);
1238 }
1239 }
1240 }
d419f42d 1241 while (!feof (fp.get ()));
85d4a676
SS
1242 }
1243
1244 buffer_grow_str0 (&buffer, "</osdata>\n");
1245 buf = buffer_finish (&buffer);
1246 len_avail = strlen (buf);
1247 }
1248
1249 if (offset >= len_avail)
1250 {
1251 /* Done. Get rid of the buffer. */
1252 buffer_free (&buffer);
1253 buf = NULL;
1254 len_avail = 0;
1255 return 0;
1256 }
1257
1258 if (len > len_avail - offset)
1259 len = len_avail - offset;
1260 memcpy (readbuf, buf + offset, len);
1261
1262 return len;
1263}
1264
1265/* Collect data about semaphores recorded in /proc and write it
1266 into READBUF. */
1267
1268static LONGEST
1269linux_xfer_osdata_sem (gdb_byte *readbuf,
dea80a27 1270 ULONGEST offset, ULONGEST len)
85d4a676
SS
1271{
1272 static const char *buf;
1273 static LONGEST len_avail = -1;
1274 static struct buffer buffer;
1275
1276 if (offset == 0)
1277 {
85d4a676
SS
1278 if (len_avail != -1 && len_avail != 0)
1279 buffer_free (&buffer);
1280 len_avail = 0;
1281 buf = NULL;
1282 buffer_init (&buffer);
1283 buffer_grow_str (&buffer, "<osdata type=\"semaphores\">\n");
1284
d419f42d 1285 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
85d4a676
SS
1286 if (fp)
1287 {
1288 char buf[8192];
1289
1290 do
1291 {
d419f42d 1292 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676
SS
1293 {
1294 key_t key;
1295 uid_t uid, cuid;
1296 gid_t gid, cgid;
1297 unsigned int perms, nsems;
1298 int semid;
1299 TIME_T otime, ctime;
1300 int items_read;
1301
1302 items_read = sscanf (buf,
1303 "%d %d %o %u %d %d %d %d %lld %lld",
1304 &key, &semid, &perms, &nsems,
1305 &uid, &gid, &cuid, &cgid,
1306 &otime, &ctime);
1307
1308 if (items_read == 10)
1309 {
1310 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1311 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1312 char otime_str[32], ctime_str[32];
1313
1314 user_from_uid (user, sizeof (user), uid);
1315 group_from_gid (group, sizeof (group), gid);
1316 user_from_uid (cuser, sizeof (cuser), cuid);
1317 group_from_gid (cgroup, sizeof (cgroup), cgid);
1318
1319 time_from_time_t (otime_str, sizeof (otime_str), otime);
1320 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1321
1322 buffer_xml_printf (
1323 &buffer,
1324 "<item>"
1325 "<column name=\"key\">%d</column>"
1326 "<column name=\"semid\">%d</column>"
1327 "<column name=\"permissions\">%o</column>"
1328 "<column name=\"num semaphores\">%u</column>"
1329 "<column name=\"user\">%s</column>"
1330 "<column name=\"group\">%s</column>"
1331 "<column name=\"creator user\">%s</column>"
1332 "<column name=\"creator group\">%s</column>"
1333 "<column name=\"last semop() time\">%s</column>"
1334 "<column name=\"last semctl() time\">%s</column>"
1335 "</item>",
1336 key,
1337 semid,
1338 perms,
1339 nsems,
1340 user,
1341 group,
1342 cuser,
1343 cgroup,
1344 otime_str,
1345 ctime_str);
1346 }
1347 }
1348 }
d419f42d 1349 while (!feof (fp.get ()));
85d4a676
SS
1350 }
1351
1352 buffer_grow_str0 (&buffer, "</osdata>\n");
1353 buf = buffer_finish (&buffer);
1354 len_avail = strlen (buf);
1355 }
1356
1357 if (offset >= len_avail)
1358 {
1359 /* Done. Get rid of the buffer. */
1360 buffer_free (&buffer);
1361 buf = NULL;
1362 len_avail = 0;
1363 return 0;
1364 }
1365
1366 if (len > len_avail - offset)
1367 len = len_avail - offset;
1368 memcpy (readbuf, buf + offset, len);
1369
1370 return len;
1371}
1372
1373/* Collect data about message queues recorded in /proc and write it
1374 into READBUF. */
1375
1376static LONGEST
1377linux_xfer_osdata_msg (gdb_byte *readbuf,
dea80a27 1378 ULONGEST offset, ULONGEST len)
85d4a676
SS
1379{
1380 static const char *buf;
1381 static LONGEST len_avail = -1;
1382 static struct buffer buffer;
1383
1384 if (offset == 0)
1385 {
85d4a676
SS
1386 if (len_avail != -1 && len_avail != 0)
1387 buffer_free (&buffer);
1388 len_avail = 0;
1389 buf = NULL;
1390 buffer_init (&buffer);
1391 buffer_grow_str (&buffer, "<osdata type=\"message queues\">\n");
1392
d419f42d 1393 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
85d4a676
SS
1394 if (fp)
1395 {
1396 char buf[8192];
1397
1398 do
1399 {
d419f42d 1400 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676
SS
1401 {
1402 key_t key;
1403 PID_T lspid, lrpid;
1404 uid_t uid, cuid;
1405 gid_t gid, cgid;
1406 unsigned int perms, cbytes, qnum;
1407 int msqid;
1408 TIME_T stime, rtime, ctime;
1409 int items_read;
1410
1411 items_read = sscanf (buf,
1412 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1413 &key, &msqid, &perms, &cbytes, &qnum,
1414 &lspid, &lrpid, &uid, &gid, &cuid, &cgid,
1415 &stime, &rtime, &ctime);
1416
1417 if (items_read == 14)
1418 {
1419 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1420 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1421 char lscmd[32], lrcmd[32];
1422 char stime_str[32], rtime_str[32], ctime_str[32];
1423
1424 user_from_uid (user, sizeof (user), uid);
1425 group_from_gid (group, sizeof (group), gid);
1426 user_from_uid (cuser, sizeof (cuser), cuid);
1427 group_from_gid (cgroup, sizeof (cgroup), cgid);
1428
1429 command_from_pid (lscmd, sizeof (lscmd), lspid);
1430 command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
1431
1432 time_from_time_t (stime_str, sizeof (stime_str), stime);
1433 time_from_time_t (rtime_str, sizeof (rtime_str), rtime);
1434 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1435
1436 buffer_xml_printf (
1437 &buffer,
1438 "<item>"
1439 "<column name=\"key\">%d</column>"
1440 "<column name=\"msqid\">%d</column>"
1441 "<column name=\"permissions\">%o</column>"
1442 "<column name=\"num used bytes\">%u</column>"
1443 "<column name=\"num messages\">%u</column>"
1444 "<column name=\"last msgsnd() command\">%s</column>"
1445 "<column name=\"last msgrcv() command\">%s</column>"
1446 "<column name=\"user\">%s</column>"
1447 "<column name=\"group\">%s</column>"
1448 "<column name=\"creator user\">%s</column>"
1449 "<column name=\"creator group\">%s</column>"
1450 "<column name=\"last msgsnd() time\">%s</column>"
1451 "<column name=\"last msgrcv() time\">%s</column>"
1452 "<column name=\"last msgctl() time\">%s</column>"
1453 "</item>",
1454 key,
1455 msqid,
1456 perms,
1457 cbytes,
1458 qnum,
1459 lscmd,
1460 lrcmd,
1461 user,
1462 group,
1463 cuser,
1464 cgroup,
1465 stime_str,
1466 rtime_str,
1467 ctime_str);
1468 }
1469 }
1470 }
d419f42d 1471 while (!feof (fp.get ()));
85d4a676
SS
1472 }
1473
1474 buffer_grow_str0 (&buffer, "</osdata>\n");
1475 buf = buffer_finish (&buffer);
1476 len_avail = strlen (buf);
1477 }
1478
1479 if (offset >= len_avail)
1480 {
1481 /* Done. Get rid of the buffer. */
1482 buffer_free (&buffer);
1483 buf = NULL;
1484 len_avail = 0;
1485 return 0;
1486 }
1487
1488 if (len > len_avail - offset)
1489 len = len_avail - offset;
1490 memcpy (readbuf, buf + offset, len);
1491
1492 return len;
1493}
1494
1495/* Collect data about loaded kernel modules and write it into
1496 READBUF. */
1497
1498static LONGEST
1499linux_xfer_osdata_modules (gdb_byte *readbuf,
dea80a27 1500 ULONGEST offset, ULONGEST len)
85d4a676
SS
1501{
1502 static const char *buf;
1503 static LONGEST len_avail = -1;
1504 static struct buffer buffer;
1505
1506 if (offset == 0)
1507 {
85d4a676
SS
1508 if (len_avail != -1 && len_avail != 0)
1509 buffer_free (&buffer);
1510 len_avail = 0;
1511 buf = NULL;
1512 buffer_init (&buffer);
1513 buffer_grow_str (&buffer, "<osdata type=\"modules\">\n");
1514
d419f42d 1515 gdb_file_up fp = gdb_fopen_cloexec ("/proc/modules", "r");
85d4a676
SS
1516 if (fp)
1517 {
1518 char buf[8192];
1519
1520 do
1521 {
d419f42d 1522 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676 1523 {
f60db4f0 1524 char *name, *dependencies, *status, *tmp;
85d4a676
SS
1525 unsigned int size;
1526 unsigned long long address;
1527 int uses;
85d4a676 1528
f60db4f0
GB
1529 name = strtok (buf, " ");
1530 if (name == NULL)
1531 continue;
1532
1533 tmp = strtok (NULL, " ");
1534 if (tmp == NULL)
1535 continue;
1536 if (sscanf (tmp, "%u", &size) != 1)
1537 continue;
1538
1539 tmp = strtok (NULL, " ");
1540 if (tmp == NULL)
1541 continue;
1542 if (sscanf (tmp, "%d", &uses) != 1)
1543 continue;
1544
1545 dependencies = strtok (NULL, " ");
1546 if (dependencies == NULL)
1547 continue;
1548
1549 status = strtok (NULL, " ");
1550 if (status == NULL)
1551 continue;
1552
1553 tmp = strtok (NULL, "\n");
1554 if (tmp == NULL)
1555 continue;
1556 if (sscanf (tmp, "%llx", &address) != 1)
1557 continue;
1558
1559 buffer_xml_printf (
85d4a676
SS
1560 &buffer,
1561 "<item>"
1562 "<column name=\"name\">%s</column>"
1563 "<column name=\"size\">%u</column>"
1564 "<column name=\"num uses\">%d</column>"
1565 "<column name=\"dependencies\">%s</column>"
1566 "<column name=\"status\">%s</column>"
1567 "<column name=\"address\">%llx</column>"
1568 "</item>",
1569 name,
1570 size,
1571 uses,
1572 dependencies,
1573 status,
1574 address);
1575 }
1576 }
d419f42d 1577 while (!feof (fp.get ()));
85d4a676
SS
1578 }
1579
1580 buffer_grow_str0 (&buffer, "</osdata>\n");
1581 buf = buffer_finish (&buffer);
1582 len_avail = strlen (buf);
1583 }
1584
1585 if (offset >= len_avail)
1586 {
1587 /* Done. Get rid of the buffer. */
1588 buffer_free (&buffer);
1589 buf = NULL;
1590 len_avail = 0;
1591 return 0;
1592 }
1593
1594 if (len > len_avail - offset)
1595 len = len_avail - offset;
1596 memcpy (readbuf, buf + offset, len);
1597
1598 return len;
1599}
1600
d26e3629 1601struct osdata_type {
a121b7c1
PA
1602 const char *type;
1603 const char *title;
1604 const char *description;
dea80a27 1605 LONGEST (*getter) (gdb_byte *readbuf, ULONGEST offset, ULONGEST len);
d26e3629 1606} osdata_table[] = {
d33279b3
AT
1607 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
1608 linux_xfer_osdata_cpus },
1609 { "files", "File descriptors", "Listing of all file descriptors",
1610 linux_xfer_osdata_fds },
1611 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
1612 linux_xfer_osdata_modules },
1613 { "msg", "Message queues", "Listing of all message queues",
1614 linux_xfer_osdata_msg },
71caed83 1615 { "processes", "Processes", "Listing of all processes",
85d4a676 1616 linux_xfer_osdata_processes },
71caed83 1617 { "procgroups", "Process groups", "Listing of all process groups",
85d4a676 1618 linux_xfer_osdata_processgroups },
71caed83 1619 { "semaphores", "Semaphores", "Listing of all semaphores",
85d4a676 1620 linux_xfer_osdata_sem },
d33279b3
AT
1621 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
1622 linux_xfer_osdata_shm },
1623 { "sockets", "Sockets", "Listing of all internet-domain sockets",
1624 linux_xfer_osdata_isockets },
1625 { "threads", "Threads", "Listing of all threads",
1626 linux_xfer_osdata_threads },
d26e3629
KY
1627 { NULL, NULL, NULL }
1628};
1629
1630LONGEST
1631linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
dea80a27 1632 ULONGEST offset, ULONGEST len)
d26e3629
KY
1633{
1634 if (!annex || *annex == '\0')
1635 {
1636 static const char *buf;
1637 static LONGEST len_avail = -1;
1638 static struct buffer buffer;
1639
1640 if (offset == 0)
1641 {
1642 int i;
1643
1644 if (len_avail != -1 && len_avail != 0)
1645 buffer_free (&buffer);
1646 len_avail = 0;
1647 buf = NULL;
1648 buffer_init (&buffer);
1649 buffer_grow_str (&buffer, "<osdata type=\"types\">\n");
1650
1651 for (i = 0; osdata_table[i].type; ++i)
1652 buffer_xml_printf (
1653 &buffer,
1654 "<item>"
1655 "<column name=\"Type\">%s</column>"
1656 "<column name=\"Description\">%s</column>"
71caed83 1657 "<column name=\"Title\">%s</column>"
d26e3629
KY
1658 "</item>",
1659 osdata_table[i].type,
71caed83
SS
1660 osdata_table[i].description,
1661 osdata_table[i].title);
d26e3629
KY
1662
1663 buffer_grow_str0 (&buffer, "</osdata>\n");
1664 buf = buffer_finish (&buffer);
1665 len_avail = strlen (buf);
1666 }
1667
1668 if (offset >= len_avail)
1669 {
1670 /* Done. Get rid of the buffer. */
1671 buffer_free (&buffer);
1672 buf = NULL;
1673 len_avail = 0;
1674 return 0;
1675 }
1676
1677 if (len > len_avail - offset)
1678 len = len_avail - offset;
1679 memcpy (readbuf, buf + offset, len);
1680
1681 return len;
1682 }
1683 else
1684 {
1685 int i;
1686
1687 for (i = 0; osdata_table[i].type; ++i)
1688 {
1689 if (strcmp (annex, osdata_table[i].type) == 0)
1690 {
1691 gdb_assert (readbuf);
1692
1693 return (osdata_table[i].getter) (readbuf, offset, len);
1694 }
1695 }
1696
1697 return 0;
1698 }
1699}
1700
This page took 0.557445 seconds and 4 git commands to generate.