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