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