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