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