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