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