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