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