Rename common to gdbsupport
[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
750b258e
PW
569 key = strtok (buf, ":");
570 if (key == NULL)
571 continue;
d33279b3 572
750b258e
PW
573 value = strtok (NULL, ":");
574 if (value == NULL)
575 continue;
d33279b3 576
750b258e
PW
577 while (key[i] != '\t' && key[i] != '\0')
578 i++;
d33279b3 579
750b258e 580 key[i] = '\0';
d33279b3 581
750b258e
PW
582 i = 0;
583 while (value[i] != '\t' && value[i] != '\0')
584 i++;
d33279b3 585
750b258e 586 value[i] = '\0';
d33279b3 587
750b258e
PW
588 if (strcmp (key, "processor") == 0)
589 {
590 if (first_item)
591 buffer_grow_str (buffer, "<item>");
592 else
593 buffer_grow_str (buffer, "</item><item>");
d33279b3 594
750b258e 595 first_item = 0;
d33279b3 596 }
d33279b3 597
750b258e
PW
598 buffer_xml_printf (buffer,
599 "<column name=\"%s\">%s</column>",
600 key,
601 value);
602 }
d33279b3 603 }
750b258e 604 while (!feof (fp.get ()));
d33279b3 605
750b258e
PW
606 if (first_item == 0)
607 buffer_grow_str (buffer, "</item>");
d33279b3
AT
608 }
609
750b258e 610 buffer_grow_str0 (buffer, "</osdata>\n");
d33279b3
AT
611}
612
85d4a676 613/* Collect all the open file descriptors found in /proc and put the details
750b258e 614 found about them into BUFFER. */
85d4a676 615
750b258e
PW
616static void
617linux_xfer_osdata_fds (struct buffer *buffer)
85d4a676 618{
750b258e 619 DIR *dirp;
85d4a676 620
750b258e 621 buffer_grow_str (buffer, "<osdata type=\"files\">\n");
85d4a676 622
750b258e
PW
623 dirp = opendir ("/proc");
624 if (dirp)
625 {
626 struct dirent *dp;
85d4a676 627
750b258e 628 while ((dp = readdir (dirp)) != NULL)
85d4a676 629 {
750b258e
PW
630 struct stat statbuf;
631 char procentry[sizeof ("/proc/4294967295")];
85d4a676 632
750b258e
PW
633 if (!isdigit (dp->d_name[0])
634 || NAMELEN (dp) > sizeof ("4294967295") - 1)
635 continue;
85d4a676 636
750b258e
PW
637 xsnprintf (procentry, sizeof (procentry), "/proc/%s",
638 dp->d_name);
639 if (stat (procentry, &statbuf) == 0
640 && S_ISDIR (statbuf.st_mode))
641 {
642 DIR *dirp2;
643 PID_T pid;
644 char command[32];
85d4a676 645
750b258e
PW
646 pid = atoi (dp->d_name);
647 command_from_pid (command, sizeof (command), pid);
85d4a676 648
750b258e
PW
649 std::string pathname
650 = string_printf ("/proc/%s/fd", dp->d_name);
651 dirp2 = opendir (pathname.c_str ());
85d4a676 652
750b258e
PW
653 if (dirp2)
654 {
655 struct dirent *dp2;
85d4a676 656
750b258e 657 while ((dp2 = readdir (dirp2)) != NULL)
85d4a676 658 {
750b258e
PW
659 char buf[1000];
660 ssize_t rslt;
661
662 if (!isdigit (dp2->d_name[0]))
663 continue;
664
665 std::string fdname
666 = string_printf ("%s/%s", pathname.c_str (),
667 dp2->d_name);
668 rslt = readlink (fdname.c_str (), buf,
669 sizeof (buf) - 1);
670 if (rslt >= 0)
671 buf[rslt] = '\0';
672
673 buffer_xml_printf
674 (buffer,
675 "<item>"
676 "<column name=\"pid\">%s</column>"
677 "<column name=\"command\">%s</column>"
678 "<column name=\"file descriptor\">%s</column>"
679 "<column name=\"name\">%s</column>"
680 "</item>",
681 dp->d_name,
682 command,
683 dp2->d_name,
684 (rslt >= 0 ? buf : dp2->d_name));
85d4a676 685 }
750b258e
PW
686
687 closedir (dirp2);
85d4a676
SS
688 }
689 }
85d4a676
SS
690 }
691
750b258e 692 closedir (dirp);
85d4a676
SS
693 }
694
750b258e 695 buffer_grow_str0 (buffer, "</osdata>\n");
85d4a676
SS
696}
697
698/* Returns the socket state STATE in textual form. */
699
700static const char *
701format_socket_state (unsigned char state)
702{
703 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */
704 enum {
705 TCP_ESTABLISHED = 1,
706 TCP_SYN_SENT,
707 TCP_SYN_RECV,
708 TCP_FIN_WAIT1,
709 TCP_FIN_WAIT2,
710 TCP_TIME_WAIT,
711 TCP_CLOSE,
712 TCP_CLOSE_WAIT,
713 TCP_LAST_ACK,
714 TCP_LISTEN,
715 TCP_CLOSING
716 };
717
718 switch (state)
719 {
720 case TCP_ESTABLISHED:
721 return "ESTABLISHED";
722 case TCP_SYN_SENT:
723 return "SYN_SENT";
724 case TCP_SYN_RECV:
725 return "SYN_RECV";
726 case TCP_FIN_WAIT1:
727 return "FIN_WAIT1";
728 case TCP_FIN_WAIT2:
729 return "FIN_WAIT2";
730 case TCP_TIME_WAIT:
731 return "TIME_WAIT";
732 case TCP_CLOSE:
733 return "CLOSE";
734 case TCP_CLOSE_WAIT:
735 return "CLOSE_WAIT";
736 case TCP_LAST_ACK:
737 return "LAST_ACK";
738 case TCP_LISTEN:
739 return "LISTEN";
740 case TCP_CLOSING:
741 return "CLOSING";
742 default:
743 return "(unknown)";
744 }
745}
746
747union socket_addr
748 {
749 struct sockaddr sa;
750 struct sockaddr_in sin;
751 struct sockaddr_in6 sin6;
752 };
753
754/* Auxiliary function used by linux_xfer_osdata_isocket. Formats
755 information for all open internet sockets of type FAMILY on the
756 system into BUFFER. If TCP is set, only TCP sockets are processed,
757 otherwise only UDP sockets are processed. */
758
759static void
760print_sockets (unsigned short family, int tcp, struct buffer *buffer)
761{
762 const char *proc_file;
85d4a676
SS
763
764 if (family == AF_INET)
765 proc_file = tcp ? "/proc/net/tcp" : "/proc/net/udp";
766 else if (family == AF_INET6)
767 proc_file = tcp ? "/proc/net/tcp6" : "/proc/net/udp6";
768 else
769 return;
770
d419f42d 771 gdb_file_up fp = gdb_fopen_cloexec (proc_file, "r");
85d4a676
SS
772 if (fp)
773 {
774 char buf[8192];
775
776 do
777 {
d419f42d 778 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676
SS
779 {
780 uid_t uid;
85d4a676 781 unsigned int local_port, remote_port, state;
85d4a676 782 char local_address[NI_MAXHOST], remote_address[NI_MAXHOST];
85d4a676
SS
783 int result;
784
f60db4f0
GB
785#if NI_MAXHOST <= 32
786#error "local_address and remote_address buffers too small"
787#endif
788
85d4a676 789 result = sscanf (buf,
f60db4f0 790 "%*d: %32[0-9A-F]:%X %32[0-9A-F]:%X %X %*X:%*X %*X:%*X %*X %d %*d %*u %*s\n",
85d4a676
SS
791 local_address, &local_port,
792 remote_address, &remote_port,
793 &state,
f60db4f0 794 &uid);
326b0c12 795
f60db4f0 796 if (result == 6)
85d4a676
SS
797 {
798 union socket_addr locaddr, remaddr;
799 size_t addr_size;
800 char user[UT_NAMESIZE];
801 char local_service[NI_MAXSERV], remote_service[NI_MAXSERV];
802
803 if (family == AF_INET)
804 {
805 sscanf (local_address, "%X",
806 &locaddr.sin.sin_addr.s_addr);
807 sscanf (remote_address, "%X",
808 &remaddr.sin.sin_addr.s_addr);
326b0c12 809
85d4a676
SS
810 locaddr.sin.sin_port = htons (local_port);
811 remaddr.sin.sin_port = htons (remote_port);
812
813 addr_size = sizeof (struct sockaddr_in);
814 }
815 else
816 {
817 sscanf (local_address, "%8X%8X%8X%8X",
818 locaddr.sin6.sin6_addr.s6_addr32,
819 locaddr.sin6.sin6_addr.s6_addr32 + 1,
820 locaddr.sin6.sin6_addr.s6_addr32 + 2,
821 locaddr.sin6.sin6_addr.s6_addr32 + 3);
822 sscanf (remote_address, "%8X%8X%8X%8X",
823 remaddr.sin6.sin6_addr.s6_addr32,
824 remaddr.sin6.sin6_addr.s6_addr32 + 1,
825 remaddr.sin6.sin6_addr.s6_addr32 + 2,
826 remaddr.sin6.sin6_addr.s6_addr32 + 3);
827
828 locaddr.sin6.sin6_port = htons (local_port);
829 remaddr.sin6.sin6_port = htons (remote_port);
326b0c12 830
85d4a676
SS
831 locaddr.sin6.sin6_flowinfo = 0;
832 remaddr.sin6.sin6_flowinfo = 0;
833 locaddr.sin6.sin6_scope_id = 0;
834 remaddr.sin6.sin6_scope_id = 0;
835
836 addr_size = sizeof (struct sockaddr_in6);
837 }
326b0c12 838
85d4a676 839 locaddr.sa.sa_family = remaddr.sa.sa_family = family;
326b0c12 840
85d4a676
SS
841 result = getnameinfo (&locaddr.sa, addr_size,
842 local_address, sizeof (local_address),
843 local_service, sizeof (local_service),
844 NI_NUMERICHOST | NI_NUMERICSERV
845 | (tcp ? 0 : NI_DGRAM));
846 if (result)
847 continue;
326b0c12 848
85d4a676
SS
849 result = getnameinfo (&remaddr.sa, addr_size,
850 remote_address,
851 sizeof (remote_address),
852 remote_service,
853 sizeof (remote_service),
854 NI_NUMERICHOST | NI_NUMERICSERV
855 | (tcp ? 0 : NI_DGRAM));
856 if (result)
857 continue;
326b0c12 858
85d4a676 859 user_from_uid (user, sizeof (user), uid);
326b0c12 860
85d4a676
SS
861 buffer_xml_printf (
862 buffer,
863 "<item>"
864 "<column name=\"local address\">%s</column>"
865 "<column name=\"local port\">%s</column>"
866 "<column name=\"remote address\">%s</column>"
867 "<column name=\"remote port\">%s</column>"
868 "<column name=\"state\">%s</column>"
869 "<column name=\"user\">%s</column>"
326b0c12 870 "<column name=\"family\">%s</column>"
85d4a676
SS
871 "<column name=\"protocol\">%s</column>"
872 "</item>",
873 local_address,
874 local_service,
875 remote_address,
876 remote_service,
877 format_socket_state (state),
878 user,
879 (family == AF_INET) ? "INET" : "INET6",
880 tcp ? "STREAM" : "DGRAM");
881 }
882 }
883 }
d419f42d 884 while (!feof (fp.get ()));
85d4a676
SS
885 }
886}
887
750b258e 888/* Collect data about internet sockets and write it into BUFFER. */
85d4a676 889
750b258e
PW
890static void
891linux_xfer_osdata_isockets (struct buffer *buffer)
85d4a676 892{
750b258e 893 buffer_grow_str (buffer, "<osdata type=\"I sockets\">\n");
85d4a676 894
750b258e
PW
895 print_sockets (AF_INET, 1, buffer);
896 print_sockets (AF_INET, 0, buffer);
897 print_sockets (AF_INET6, 1, buffer);
898 print_sockets (AF_INET6, 0, buffer);
85d4a676 899
750b258e 900 buffer_grow_str0 (buffer, "</osdata>\n");
85d4a676
SS
901}
902
903/* Converts the time SECONDS into textual form and copies it into a
904 buffer TIME, with at most MAXLEN characters copied. */
905
906static void
907time_from_time_t (char *time, int maxlen, TIME_T seconds)
908{
909 if (!seconds)
910 time[0] = '\0';
911 else
912 {
913 time_t t = (time_t) seconds;
326b0c12 914
85d4a676
SS
915 strncpy (time, ctime (&t), maxlen);
916 time[maxlen - 1] = '\0';
917 }
918}
919
920/* Finds the group name for the group GID and copies it into GROUP.
921 At most MAXLEN characters are copied. */
922
923static void
924group_from_gid (char *group, int maxlen, gid_t gid)
925{
926 struct group *grentry = getgrgid (gid);
326b0c12 927
85d4a676
SS
928 if (grentry)
929 {
930 strncpy (group, grentry->gr_name, maxlen);
931 /* Ensure that the group name is null-terminated. */
932 group[maxlen - 1] = '\0';
933 }
934 else
935 group[0] = '\0';
936}
937
938/* Collect data about shared memory recorded in /proc and write it
750b258e 939 into BUFFER. */
85d4a676 940
750b258e
PW
941static void
942linux_xfer_osdata_shm (struct buffer *buffer)
85d4a676 943{
750b258e 944 buffer_grow_str (buffer, "<osdata type=\"shared memory\">\n");
85d4a676 945
750b258e
PW
946 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
947 if (fp)
85d4a676 948 {
750b258e 949 char buf[8192];
85d4a676 950
750b258e
PW
951 do
952 {
953 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676 954 {
750b258e
PW
955 key_t key;
956 uid_t uid, cuid;
957 gid_t gid, cgid;
958 PID_T cpid, lpid;
959 int shmid, size, nattch;
960 TIME_T atime, dtime, ctime;
961 unsigned int perms;
962 int items_read;
963
964 items_read = sscanf (buf,
965 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld",
966 &key, &shmid, &perms, &size,
967 &cpid, &lpid,
968 &nattch,
969 &uid, &gid, &cuid, &cgid,
970 &atime, &dtime, &ctime);
971
972 if (items_read == 14)
85d4a676 973 {
750b258e
PW
974 char user[UT_NAMESIZE], group[UT_NAMESIZE];
975 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
976 char ccmd[32], lcmd[32];
977 char atime_str[32], dtime_str[32], ctime_str[32];
978
979 user_from_uid (user, sizeof (user), uid);
980 group_from_gid (group, sizeof (group), gid);
981 user_from_uid (cuser, sizeof (cuser), cuid);
982 group_from_gid (cgroup, sizeof (cgroup), cgid);
983
984 command_from_pid (ccmd, sizeof (ccmd), cpid);
985 command_from_pid (lcmd, sizeof (lcmd), lpid);
986
987 time_from_time_t (atime_str, sizeof (atime_str), atime);
988 time_from_time_t (dtime_str, sizeof (dtime_str), dtime);
989 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
990
991 buffer_xml_printf
992 (buffer,
993 "<item>"
994 "<column name=\"key\">%d</column>"
995 "<column name=\"shmid\">%d</column>"
996 "<column name=\"permissions\">%o</column>"
997 "<column name=\"size\">%d</column>"
998 "<column name=\"creator command\">%s</column>"
999 "<column name=\"last op. command\">%s</column>"
1000 "<column name=\"num attached\">%d</column>"
1001 "<column name=\"user\">%s</column>"
1002 "<column name=\"group\">%s</column>"
1003 "<column name=\"creator user\">%s</column>"
1004 "<column name=\"creator group\">%s</column>"
1005 "<column name=\"last shmat() time\">%s</column>"
1006 "<column name=\"last shmdt() time\">%s</column>"
1007 "<column name=\"last shmctl() time\">%s</column>"
1008 "</item>",
1009 key,
1010 shmid,
1011 perms,
1012 size,
1013 ccmd,
1014 lcmd,
1015 nattch,
1016 user,
1017 group,
1018 cuser,
1019 cgroup,
1020 atime_str,
1021 dtime_str,
1022 ctime_str);
85d4a676
SS
1023 }
1024 }
85d4a676 1025 }
750b258e 1026 while (!feof (fp.get ()));
85d4a676
SS
1027 }
1028
750b258e 1029 buffer_grow_str0 (buffer, "</osdata>\n");
85d4a676
SS
1030}
1031
1032/* Collect data about semaphores recorded in /proc and write it
750b258e 1033 into BUFFER. */
85d4a676 1034
750b258e
PW
1035static void
1036linux_xfer_osdata_sem (struct buffer *buffer)
85d4a676 1037{
750b258e 1038 buffer_grow_str (buffer, "<osdata type=\"semaphores\">\n");
85d4a676 1039
750b258e
PW
1040 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
1041 if (fp)
85d4a676 1042 {
750b258e 1043 char buf[8192];
326b0c12 1044
750b258e
PW
1045 do
1046 {
1047 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676 1048 {
750b258e
PW
1049 key_t key;
1050 uid_t uid, cuid;
1051 gid_t gid, cgid;
1052 unsigned int perms, nsems;
1053 int semid;
1054 TIME_T otime, ctime;
1055 int items_read;
1056
1057 items_read = sscanf (buf,
1058 "%d %d %o %u %d %d %d %d %lld %lld",
1059 &key, &semid, &perms, &nsems,
1060 &uid, &gid, &cuid, &cgid,
1061 &otime, &ctime);
1062
1063 if (items_read == 10)
85d4a676 1064 {
750b258e
PW
1065 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1066 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1067 char otime_str[32], ctime_str[32];
1068
1069 user_from_uid (user, sizeof (user), uid);
1070 group_from_gid (group, sizeof (group), gid);
1071 user_from_uid (cuser, sizeof (cuser), cuid);
1072 group_from_gid (cgroup, sizeof (cgroup), cgid);
1073
1074 time_from_time_t (otime_str, sizeof (otime_str), otime);
1075 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1076
1077 buffer_xml_printf
1078 (buffer,
1079 "<item>"
1080 "<column name=\"key\">%d</column>"
1081 "<column name=\"semid\">%d</column>"
1082 "<column name=\"permissions\">%o</column>"
1083 "<column name=\"num semaphores\">%u</column>"
1084 "<column name=\"user\">%s</column>"
1085 "<column name=\"group\">%s</column>"
1086 "<column name=\"creator user\">%s</column>"
1087 "<column name=\"creator group\">%s</column>"
1088 "<column name=\"last semop() time\">%s</column>"
1089 "<column name=\"last semctl() time\">%s</column>"
1090 "</item>",
1091 key,
1092 semid,
1093 perms,
1094 nsems,
1095 user,
1096 group,
1097 cuser,
1098 cgroup,
1099 otime_str,
1100 ctime_str);
85d4a676
SS
1101 }
1102 }
85d4a676 1103 }
750b258e 1104 while (!feof (fp.get ()));
85d4a676
SS
1105 }
1106
750b258e 1107 buffer_grow_str0 (buffer, "</osdata>\n");
85d4a676
SS
1108}
1109
1110/* Collect data about message queues recorded in /proc and write it
750b258e 1111 into BUFFER. */
85d4a676 1112
750b258e
PW
1113static void
1114linux_xfer_osdata_msg (struct buffer *buffer)
85d4a676 1115{
750b258e 1116 buffer_grow_str (buffer, "<osdata type=\"message queues\">\n");
85d4a676 1117
750b258e
PW
1118 gdb_file_up fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
1119 if (fp)
85d4a676 1120 {
750b258e 1121 char buf[8192];
326b0c12 1122
750b258e
PW
1123 do
1124 {
1125 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676 1126 {
750b258e
PW
1127 key_t key;
1128 PID_T lspid, lrpid;
1129 uid_t uid, cuid;
1130 gid_t gid, cgid;
1131 unsigned int perms, cbytes, qnum;
1132 int msqid;
1133 TIME_T stime, rtime, ctime;
1134 int items_read;
1135
1136 items_read = sscanf (buf,
1137 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld",
1138 &key, &msqid, &perms, &cbytes, &qnum,
1139 &lspid, &lrpid, &uid, &gid, &cuid, &cgid,
1140 &stime, &rtime, &ctime);
1141
1142 if (items_read == 14)
85d4a676 1143 {
750b258e
PW
1144 char user[UT_NAMESIZE], group[UT_NAMESIZE];
1145 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE];
1146 char lscmd[32], lrcmd[32];
1147 char stime_str[32], rtime_str[32], ctime_str[32];
1148
1149 user_from_uid (user, sizeof (user), uid);
1150 group_from_gid (group, sizeof (group), gid);
1151 user_from_uid (cuser, sizeof (cuser), cuid);
1152 group_from_gid (cgroup, sizeof (cgroup), cgid);
1153
1154 command_from_pid (lscmd, sizeof (lscmd), lspid);
1155 command_from_pid (lrcmd, sizeof (lrcmd), lrpid);
1156
1157 time_from_time_t (stime_str, sizeof (stime_str), stime);
1158 time_from_time_t (rtime_str, sizeof (rtime_str), rtime);
1159 time_from_time_t (ctime_str, sizeof (ctime_str), ctime);
1160
1161 buffer_xml_printf
1162 (buffer,
1163 "<item>"
1164 "<column name=\"key\">%d</column>"
1165 "<column name=\"msqid\">%d</column>"
1166 "<column name=\"permissions\">%o</column>"
1167 "<column name=\"num used bytes\">%u</column>"
1168 "<column name=\"num messages\">%u</column>"
1169 "<column name=\"last msgsnd() command\">%s</column>"
1170 "<column name=\"last msgrcv() command\">%s</column>"
1171 "<column name=\"user\">%s</column>"
1172 "<column name=\"group\">%s</column>"
1173 "<column name=\"creator user\">%s</column>"
1174 "<column name=\"creator group\">%s</column>"
1175 "<column name=\"last msgsnd() time\">%s</column>"
1176 "<column name=\"last msgrcv() time\">%s</column>"
1177 "<column name=\"last msgctl() time\">%s</column>"
1178 "</item>",
1179 key,
1180 msqid,
1181 perms,
1182 cbytes,
1183 qnum,
1184 lscmd,
1185 lrcmd,
1186 user,
1187 group,
1188 cuser,
1189 cgroup,
1190 stime_str,
1191 rtime_str,
1192 ctime_str);
85d4a676
SS
1193 }
1194 }
85d4a676 1195 }
750b258e 1196 while (!feof (fp.get ()));
85d4a676
SS
1197 }
1198
750b258e 1199 buffer_grow_str0 (buffer, "</osdata>\n");
85d4a676
SS
1200}
1201
1202/* Collect data about loaded kernel modules and write it into
750b258e 1203 BUFFER. */
85d4a676 1204
750b258e
PW
1205static void
1206linux_xfer_osdata_modules (struct buffer *buffer)
85d4a676 1207{
750b258e 1208 buffer_grow_str (buffer, "<osdata type=\"modules\">\n");
85d4a676 1209
750b258e
PW
1210 gdb_file_up fp = gdb_fopen_cloexec ("/proc/modules", "r");
1211 if (fp)
85d4a676 1212 {
750b258e 1213 char buf[8192];
326b0c12 1214
750b258e
PW
1215 do
1216 {
1217 if (fgets (buf, sizeof (buf), fp.get ()))
85d4a676 1218 {
750b258e
PW
1219 char *name, *dependencies, *status, *tmp;
1220 unsigned int size;
1221 unsigned long long address;
1222 int uses;
85d4a676 1223
750b258e
PW
1224 name = strtok (buf, " ");
1225 if (name == NULL)
1226 continue;
f60db4f0 1227
750b258e
PW
1228 tmp = strtok (NULL, " ");
1229 if (tmp == NULL)
1230 continue;
1231 if (sscanf (tmp, "%u", &size) != 1)
1232 continue;
f60db4f0 1233
750b258e
PW
1234 tmp = strtok (NULL, " ");
1235 if (tmp == NULL)
1236 continue;
1237 if (sscanf (tmp, "%d", &uses) != 1)
1238 continue;
f60db4f0 1239
750b258e
PW
1240 dependencies = strtok (NULL, " ");
1241 if (dependencies == NULL)
1242 continue;
f60db4f0 1243
750b258e
PW
1244 status = strtok (NULL, " ");
1245 if (status == NULL)
1246 continue;
f60db4f0 1247
750b258e
PW
1248 tmp = strtok (NULL, "\n");
1249 if (tmp == NULL)
1250 continue;
1251 if (sscanf (tmp, "%llx", &address) != 1)
1252 continue;
f60db4f0 1253
750b258e
PW
1254 buffer_xml_printf (buffer,
1255 "<item>"
1256 "<column name=\"name\">%s</column>"
1257 "<column name=\"size\">%u</column>"
1258 "<column name=\"num uses\">%d</column>"
1259 "<column name=\"dependencies\">%s</column>"
1260 "<column name=\"status\">%s</column>"
1261 "<column name=\"address\">%llx</column>"
1262 "</item>",
1263 name,
1264 size,
1265 uses,
1266 dependencies,
1267 status,
1268 address);
85d4a676 1269 }
85d4a676 1270 }
750b258e 1271 while (!feof (fp.get ()));
85d4a676
SS
1272 }
1273
750b258e 1274 buffer_grow_str0 (buffer, "</osdata>\n");
85d4a676
SS
1275}
1276
c8749e58 1277static void linux_xfer_osdata_info_os_types (struct buffer *buffer);
750b258e 1278
d26e3629 1279struct osdata_type {
a121b7c1
PA
1280 const char *type;
1281 const char *title;
1282 const char *description;
750b258e
PW
1283 void (*take_snapshot) (struct buffer *buffer);
1284 LONGEST len_avail;
1285 struct buffer buffer;
d26e3629 1286} osdata_table[] = {
750b258e
PW
1287 { "types", "Types", "Listing of info os types you can list",
1288 linux_xfer_osdata_info_os_types, -1 },
d33279b3 1289 { "cpus", "CPUs", "Listing of all cpus/cores on the system",
750b258e 1290 linux_xfer_osdata_cpus, -1 },
d33279b3 1291 { "files", "File descriptors", "Listing of all file descriptors",
750b258e 1292 linux_xfer_osdata_fds, -1 },
d33279b3 1293 { "modules", "Kernel modules", "Listing of all loaded kernel modules",
750b258e 1294 linux_xfer_osdata_modules, -1 },
d33279b3 1295 { "msg", "Message queues", "Listing of all message queues",
750b258e 1296 linux_xfer_osdata_msg, -1 },
71caed83 1297 { "processes", "Processes", "Listing of all processes",
750b258e 1298 linux_xfer_osdata_processes, -1 },
71caed83 1299 { "procgroups", "Process groups", "Listing of all process groups",
750b258e 1300 linux_xfer_osdata_processgroups, -1 },
71caed83 1301 { "semaphores", "Semaphores", "Listing of all semaphores",
750b258e 1302 linux_xfer_osdata_sem, -1 },
d33279b3 1303 { "shm", "Shared-memory regions", "Listing of all shared-memory regions",
750b258e 1304 linux_xfer_osdata_shm, -1 },
d33279b3 1305 { "sockets", "Sockets", "Listing of all internet-domain sockets",
750b258e 1306 linux_xfer_osdata_isockets, -1 },
d33279b3 1307 { "threads", "Threads", "Listing of all threads",
750b258e 1308 linux_xfer_osdata_threads, -1 },
d26e3629
KY
1309 { NULL, NULL, NULL }
1310};
1311
750b258e
PW
1312/* Collect data about all types info os can show in BUFFER. */
1313
1314static void
1315linux_xfer_osdata_info_os_types (struct buffer *buffer)
d26e3629 1316{
750b258e
PW
1317 buffer_grow_str (buffer, "<osdata type=\"types\">\n");
1318
1319 /* Start the below loop at 1, as we do not want to list ourselves. */
1320 for (int i = 1; osdata_table[i].type; ++i)
1321 buffer_xml_printf (buffer,
1322 "<item>"
1323 "<column name=\"Type\">%s</column>"
1324 "<column name=\"Description\">%s</column>"
1325 "<column name=\"Title\">%s</column>"
1326 "</item>",
1327 osdata_table[i].type,
1328 osdata_table[i].description,
1329 osdata_table[i].title);
1330
1331 buffer_grow_str0 (buffer, "</osdata>\n");
1332}
d26e3629 1333
d26e3629 1334
750b258e
PW
1335/* Copies up to LEN bytes in READBUF from offset OFFSET in OSD->BUFFER.
1336 If OFFSET is zero, first calls OSD->TAKE_SNAPSHOT. */
d26e3629 1337
750b258e
PW
1338static LONGEST
1339common_getter (struct osdata_type *osd,
1340 gdb_byte *readbuf, ULONGEST offset, ULONGEST len)
1341{
1342 gdb_assert (readbuf);
1343
1344 if (offset == 0)
1345 {
1346 if (osd->len_avail != -1 && osd->len_avail != 0)
1347 buffer_free (&osd->buffer);
1348 osd->len_avail = 0;
1349 buffer_init (&osd->buffer);
1350 (osd->take_snapshot) (&osd->buffer);
1351 osd->len_avail = strlen (osd->buffer.buffer);
1352 }
1353 if (offset >= osd->len_avail)
1354 {
1355 /* Done. Get rid of the buffer. */
1356 buffer_free (&osd->buffer);
1357 osd->len_avail = 0;
1358 return 0;
1359 }
1360 if (len > osd->len_avail - offset)
1361 len = osd->len_avail - offset;
1362 memcpy (readbuf, osd->buffer.buffer + offset, len);
d26e3629 1363
750b258e
PW
1364 return len;
1365
1366}
d26e3629 1367
750b258e
PW
1368LONGEST
1369linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf,
1370 ULONGEST offset, ULONGEST len)
1371{
1372 if (!annex || *annex == '\0')
1373 {
1374 return common_getter (&osdata_table[0],
1375 readbuf, offset, len);
d26e3629
KY
1376 }
1377 else
1378 {
1379 int i;
1380
1381 for (i = 0; osdata_table[i].type; ++i)
1382 {
1383 if (strcmp (annex, osdata_table[i].type) == 0)
750b258e
PW
1384 return common_getter (&osdata_table[i],
1385 readbuf, offset, len);
d26e3629
KY
1386 }
1387
1388 return 0;
1389 }
1390}
This page took 0.714687 seconds and 4 git commands to generate.