GDB (API)
|
00001 /* Linux-specific functions to retrieve OS data. 00002 00003 Copyright (C) 2009-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #ifdef GDBSERVER 00021 #include "server.h" 00022 #else 00023 #include "defs.h" 00024 #endif 00025 00026 #include "linux-osdata.h" 00027 00028 #include <sys/types.h> 00029 #include <sys/sysinfo.h> 00030 #include <ctype.h> 00031 #include <stdlib.h> 00032 #include <string.h> 00033 #include <utmp.h> 00034 #include <time.h> 00035 #include <unistd.h> 00036 #include <pwd.h> 00037 #include <grp.h> 00038 #include <netdb.h> 00039 #include <netinet/in.h> 00040 #include <arpa/inet.h> 00041 00042 #include "xml-utils.h" 00043 #include "buffer.h" 00044 #include "gdb_assert.h" 00045 #include "gdb_dirent.h" 00046 #include "gdb_stat.h" 00047 #include "filestuff.h" 00048 00049 /* Define PID_T to be a fixed size that is at least as large as pid_t, 00050 so that reading pid values embedded in /proc works 00051 consistently. */ 00052 00053 typedef long long PID_T; 00054 00055 /* Define TIME_T to be at least as large as time_t, so that reading 00056 time values embedded in /proc works consistently. */ 00057 00058 typedef long long TIME_T; 00059 00060 #define MAX_PID_T_STRLEN (sizeof ("-9223372036854775808") - 1) 00061 00062 /* Returns the CPU core that thread PTID is currently running on. */ 00063 00064 /* Compute and return the processor core of a given thread. */ 00065 00066 int 00067 linux_common_core_of_thread (ptid_t ptid) 00068 { 00069 char filename[sizeof ("/proc//task//stat") + 2 * MAX_PID_T_STRLEN]; 00070 FILE *f; 00071 char *content = NULL; 00072 char *p; 00073 char *ts = 0; 00074 int content_read = 0; 00075 int i; 00076 int core; 00077 00078 sprintf (filename, "/proc/%lld/task/%lld/stat", 00079 (PID_T) ptid_get_pid (ptid), (PID_T) ptid_get_lwp (ptid)); 00080 f = gdb_fopen_cloexec (filename, "r"); 00081 if (!f) 00082 return -1; 00083 00084 for (;;) 00085 { 00086 int n; 00087 content = xrealloc (content, content_read + 1024); 00088 n = fread (content + content_read, 1, 1024, f); 00089 content_read += n; 00090 if (n < 1024) 00091 { 00092 content[content_read] = '\0'; 00093 break; 00094 } 00095 } 00096 00097 p = strchr (content, '('); 00098 00099 /* Skip ")". */ 00100 if (p != NULL) 00101 p = strchr (p, ')'); 00102 if (p != NULL) 00103 p++; 00104 00105 /* If the first field after program name has index 0, then core number is 00106 the field with index 36. There's no constant for that anywhere. */ 00107 if (p != NULL) 00108 p = strtok_r (p, " ", &ts); 00109 for (i = 0; p != NULL && i != 36; ++i) 00110 p = strtok_r (NULL, " ", &ts); 00111 00112 if (p == NULL || sscanf (p, "%d", &core) == 0) 00113 core = -1; 00114 00115 xfree (content); 00116 fclose (f); 00117 00118 return core; 00119 } 00120 00121 /* Finds the command-line of process PID and copies it into COMMAND. 00122 At most MAXLEN characters are copied. If the command-line cannot 00123 be found, PID is copied into command in text-form. */ 00124 00125 static void 00126 command_from_pid (char *command, int maxlen, PID_T pid) 00127 { 00128 char *stat_path = xstrprintf ("/proc/%lld/stat", pid); 00129 FILE *fp = gdb_fopen_cloexec (stat_path, "r"); 00130 00131 command[0] = '\0'; 00132 00133 if (fp) 00134 { 00135 /* sizeof (cmd) should be greater or equal to TASK_COMM_LEN (in 00136 include/linux/sched.h in the Linux kernel sources) plus two 00137 (for the brackets). */ 00138 char cmd[32]; 00139 PID_T stat_pid; 00140 int items_read = fscanf (fp, "%lld %32s", &stat_pid, cmd); 00141 00142 if (items_read == 2 && pid == stat_pid) 00143 { 00144 cmd[strlen (cmd) - 1] = '\0'; /* Remove trailing parenthesis. */ 00145 strncpy (command, cmd + 1, maxlen); /* Ignore leading parenthesis. */ 00146 } 00147 00148 fclose (fp); 00149 } 00150 else 00151 { 00152 /* Return the PID if a /proc entry for the process cannot be found. */ 00153 snprintf (command, maxlen, "%lld", pid); 00154 } 00155 00156 command[maxlen - 1] = '\0'; /* Ensure string is null-terminated. */ 00157 00158 xfree (stat_path); 00159 } 00160 00161 /* Returns the command-line of the process with the given PID. The 00162 returned string needs to be freed using xfree after use. */ 00163 00164 static char * 00165 commandline_from_pid (PID_T pid) 00166 { 00167 char *pathname = xstrprintf ("/proc/%lld/cmdline", pid); 00168 char *commandline = NULL; 00169 FILE *f = gdb_fopen_cloexec (pathname, "r"); 00170 00171 if (f) 00172 { 00173 size_t len = 0; 00174 00175 while (!feof (f)) 00176 { 00177 char buf[1024]; 00178 size_t read_bytes = fread (buf, 1, sizeof (buf), f); 00179 00180 if (read_bytes) 00181 { 00182 commandline = (char *) xrealloc (commandline, len + read_bytes + 1); 00183 memcpy (commandline + len, buf, read_bytes); 00184 len += read_bytes; 00185 } 00186 } 00187 00188 fclose (f); 00189 00190 if (commandline) 00191 { 00192 size_t i; 00193 00194 /* Replace null characters with spaces. */ 00195 for (i = 0; i < len; ++i) 00196 if (commandline[i] == '\0') 00197 commandline[i] = ' '; 00198 00199 commandline[len] = '\0'; 00200 } 00201 else 00202 { 00203 /* Return the command in square brackets if the command-line 00204 is empty. */ 00205 commandline = (char *) xmalloc (32); 00206 commandline[0] = '['; 00207 command_from_pid (commandline + 1, 31, pid); 00208 00209 len = strlen (commandline); 00210 if (len < 31) 00211 strcat (commandline, "]"); 00212 } 00213 } 00214 00215 xfree (pathname); 00216 00217 return commandline; 00218 } 00219 00220 /* Finds the user name for the user UID and copies it into USER. At 00221 most MAXLEN characters are copied. */ 00222 00223 static void 00224 user_from_uid (char *user, int maxlen, uid_t uid) 00225 { 00226 struct passwd *pwentry = getpwuid (uid); 00227 00228 if (pwentry) 00229 { 00230 strncpy (user, pwentry->pw_name, maxlen); 00231 /* Ensure that the user name is null-terminated. */ 00232 user[maxlen - 1] = '\0'; 00233 } 00234 else 00235 user[0] = '\0'; 00236 } 00237 00238 /* Finds the owner of process PID and returns the user id in OWNER. 00239 Returns 0 if the owner was found, -1 otherwise. */ 00240 00241 static int 00242 get_process_owner (uid_t *owner, PID_T pid) 00243 { 00244 struct stat statbuf; 00245 char procentry[sizeof ("/proc/") + MAX_PID_T_STRLEN]; 00246 00247 sprintf (procentry, "/proc/%lld", pid); 00248 00249 if (stat (procentry, &statbuf) == 0 && S_ISDIR (statbuf.st_mode)) 00250 { 00251 *owner = statbuf.st_uid; 00252 return 0; 00253 } 00254 else 00255 return -1; 00256 } 00257 00258 /* Find the CPU cores used by process PID and return them in CORES. 00259 CORES points to an array of at least sysconf(_SC_NPROCESSOR_ONLN) 00260 elements. */ 00261 00262 static int 00263 get_cores_used_by_process (PID_T pid, int *cores) 00264 { 00265 char taskdir[sizeof ("/proc/") + MAX_PID_T_STRLEN + sizeof ("/task") - 1]; 00266 DIR *dir; 00267 struct dirent *dp; 00268 int task_count = 0; 00269 00270 sprintf (taskdir, "/proc/%lld/task", pid); 00271 dir = opendir (taskdir); 00272 if (dir) 00273 { 00274 while ((dp = readdir (dir)) != NULL) 00275 { 00276 PID_T tid; 00277 int core; 00278 00279 if (!isdigit (dp->d_name[0]) 00280 || NAMELEN (dp) > MAX_PID_T_STRLEN) 00281 continue; 00282 00283 sscanf (dp->d_name, "%lld", &tid); 00284 core = linux_common_core_of_thread (ptid_build ((pid_t) pid, 00285 (pid_t) tid, 0)); 00286 00287 if (core >= 0) 00288 { 00289 ++cores[core]; 00290 ++task_count; 00291 } 00292 } 00293 00294 closedir (dir); 00295 } 00296 00297 return task_count; 00298 } 00299 00300 static LONGEST 00301 linux_xfer_osdata_processes (gdb_byte *readbuf, 00302 ULONGEST offset, LONGEST len) 00303 { 00304 /* We make the process list snapshot when the object starts to be read. */ 00305 static const char *buf; 00306 static LONGEST len_avail = -1; 00307 static struct buffer buffer; 00308 00309 if (offset == 0) 00310 { 00311 DIR *dirp; 00312 00313 if (len_avail != -1 && len_avail != 0) 00314 buffer_free (&buffer); 00315 len_avail = 0; 00316 buf = NULL; 00317 buffer_init (&buffer); 00318 buffer_grow_str (&buffer, "<osdata type=\"processes\">\n"); 00319 00320 dirp = opendir ("/proc"); 00321 if (dirp) 00322 { 00323 const int num_cores = sysconf (_SC_NPROCESSORS_ONLN); 00324 struct dirent *dp; 00325 00326 while ((dp = readdir (dirp)) != NULL) 00327 { 00328 PID_T pid; 00329 uid_t owner; 00330 char user[UT_NAMESIZE]; 00331 char *command_line; 00332 int *cores; 00333 int task_count; 00334 char *cores_str; 00335 int i; 00336 00337 if (!isdigit (dp->d_name[0]) 00338 || NAMELEN (dp) > MAX_PID_T_STRLEN) 00339 continue; 00340 00341 sscanf (dp->d_name, "%lld", &pid); 00342 command_line = commandline_from_pid (pid); 00343 00344 if (get_process_owner (&owner, pid) == 0) 00345 user_from_uid (user, sizeof (user), owner); 00346 else 00347 strcpy (user, "?"); 00348 00349 /* Find CPU cores used by the process. */ 00350 cores = (int *) xcalloc (num_cores, sizeof (int)); 00351 task_count = get_cores_used_by_process (pid, cores); 00352 cores_str = (char *) xcalloc (task_count, sizeof ("4294967295") + 1); 00353 00354 for (i = 0; i < num_cores && task_count > 0; ++i) 00355 if (cores[i]) 00356 { 00357 char core_str[sizeof ("4294967295")]; 00358 00359 sprintf (core_str, "%d", i); 00360 strcat (cores_str, core_str); 00361 00362 task_count -= cores[i]; 00363 if (task_count > 0) 00364 strcat (cores_str, ","); 00365 } 00366 00367 xfree (cores); 00368 00369 buffer_xml_printf ( 00370 &buffer, 00371 "<item>" 00372 "<column name=\"pid\">%lld</column>" 00373 "<column name=\"user\">%s</column>" 00374 "<column name=\"command\">%s</column>" 00375 "<column name=\"cores\">%s</column>" 00376 "</item>", 00377 pid, 00378 user, 00379 command_line ? command_line : "", 00380 cores_str); 00381 00382 xfree (command_line); 00383 xfree (cores_str); 00384 } 00385 00386 closedir (dirp); 00387 } 00388 00389 buffer_grow_str0 (&buffer, "</osdata>\n"); 00390 buf = buffer_finish (&buffer); 00391 len_avail = strlen (buf); 00392 } 00393 00394 if (offset >= len_avail) 00395 { 00396 /* Done. Get rid of the buffer. */ 00397 buffer_free (&buffer); 00398 buf = NULL; 00399 len_avail = 0; 00400 return 0; 00401 } 00402 00403 if (len > len_avail - offset) 00404 len = len_avail - offset; 00405 memcpy (readbuf, buf + offset, len); 00406 00407 return len; 00408 } 00409 00410 /* Auxiliary function used by qsort to sort processes by process 00411 group. Compares two processes with ids PROCESS1 and PROCESS2. 00412 PROCESS1 comes before PROCESS2 if it has a lower process group id. 00413 If they belong to the same process group, PROCESS1 comes before 00414 PROCESS2 if it has a lower process id or is the process group 00415 leader. */ 00416 00417 static int 00418 compare_processes (const void *process1, const void *process2) 00419 { 00420 PID_T pid1 = *((PID_T *) process1); 00421 PID_T pid2 = *((PID_T *) process2); 00422 PID_T pgid1 = *((PID_T *) process1 + 1); 00423 PID_T pgid2 = *((PID_T *) process2 + 1); 00424 00425 /* Sort by PGID. */ 00426 if (pgid1 < pgid2) 00427 return -1; 00428 else if (pgid1 > pgid2) 00429 return 1; 00430 else 00431 { 00432 /* Process group leaders always come first, else sort by PID. */ 00433 if (pid1 == pgid1) 00434 return -1; 00435 else if (pid2 == pgid2) 00436 return 1; 00437 else if (pid1 < pid2) 00438 return -1; 00439 else if (pid1 > pid2) 00440 return 1; 00441 else 00442 return 0; 00443 } 00444 } 00445 00446 /* Collect all process groups from /proc. */ 00447 00448 static LONGEST 00449 linux_xfer_osdata_processgroups (gdb_byte *readbuf, 00450 ULONGEST offset, LONGEST len) 00451 { 00452 /* We make the process list snapshot when the object starts to be read. */ 00453 static const char *buf; 00454 static LONGEST len_avail = -1; 00455 static struct buffer buffer; 00456 00457 if (offset == 0) 00458 { 00459 DIR *dirp; 00460 00461 if (len_avail != -1 && len_avail != 0) 00462 buffer_free (&buffer); 00463 len_avail = 0; 00464 buf = NULL; 00465 buffer_init (&buffer); 00466 buffer_grow_str (&buffer, "<osdata type=\"process groups\">\n"); 00467 00468 dirp = opendir ("/proc"); 00469 if (dirp) 00470 { 00471 struct dirent *dp; 00472 const size_t list_block_size = 512; 00473 PID_T *process_list = (PID_T *) xmalloc (list_block_size * 2 * sizeof (PID_T)); 00474 size_t process_count = 0; 00475 size_t i; 00476 00477 /* Build list consisting of PIDs followed by their 00478 associated PGID. */ 00479 while ((dp = readdir (dirp)) != NULL) 00480 { 00481 PID_T pid, pgid; 00482 00483 if (!isdigit (dp->d_name[0]) 00484 || NAMELEN (dp) > MAX_PID_T_STRLEN) 00485 continue; 00486 00487 sscanf (dp->d_name, "%lld", &pid); 00488 pgid = getpgid (pid); 00489 00490 if (pgid > 0) 00491 { 00492 process_list[2 * process_count] = pid; 00493 process_list[2 * process_count + 1] = pgid; 00494 ++process_count; 00495 00496 /* Increase the size of the list if necessary. */ 00497 if (process_count % list_block_size == 0) 00498 process_list = (PID_T *) xrealloc ( 00499 process_list, 00500 (process_count + list_block_size) 00501 * 2 * sizeof (PID_T)); 00502 } 00503 } 00504 00505 closedir (dirp); 00506 00507 /* Sort the process list. */ 00508 qsort (process_list, process_count, 2 * sizeof (PID_T), 00509 compare_processes); 00510 00511 for (i = 0; i < process_count; ++i) 00512 { 00513 PID_T pid = process_list[2 * i]; 00514 PID_T pgid = process_list[2 * i + 1]; 00515 char leader_command[32]; 00516 char *command_line; 00517 00518 command_from_pid (leader_command, sizeof (leader_command), pgid); 00519 command_line = commandline_from_pid (pid); 00520 00521 buffer_xml_printf ( 00522 &buffer, 00523 "<item>" 00524 "<column name=\"pgid\">%lld</column>" 00525 "<column name=\"leader command\">%s</column>" 00526 "<column name=\"pid\">%lld</column>" 00527 "<column name=\"command line\">%s</column>" 00528 "</item>", 00529 pgid, 00530 leader_command, 00531 pid, 00532 command_line ? command_line : ""); 00533 00534 xfree (command_line); 00535 } 00536 00537 xfree (process_list); 00538 } 00539 00540 buffer_grow_str0 (&buffer, "</osdata>\n"); 00541 buf = buffer_finish (&buffer); 00542 len_avail = strlen (buf); 00543 } 00544 00545 if (offset >= len_avail) 00546 { 00547 /* Done. Get rid of the buffer. */ 00548 buffer_free (&buffer); 00549 buf = NULL; 00550 len_avail = 0; 00551 return 0; 00552 } 00553 00554 if (len > len_avail - offset) 00555 len = len_avail - offset; 00556 memcpy (readbuf, buf + offset, len); 00557 00558 return len; 00559 } 00560 00561 /* Collect all the threads in /proc by iterating through processes and 00562 then tasks within each process. */ 00563 00564 static LONGEST 00565 linux_xfer_osdata_threads (gdb_byte *readbuf, 00566 ULONGEST offset, LONGEST len) 00567 { 00568 /* We make the process list snapshot when the object starts to be read. */ 00569 static const char *buf; 00570 static LONGEST len_avail = -1; 00571 static struct buffer buffer; 00572 00573 if (offset == 0) 00574 { 00575 DIR *dirp; 00576 00577 if (len_avail != -1 && len_avail != 0) 00578 buffer_free (&buffer); 00579 len_avail = 0; 00580 buf = NULL; 00581 buffer_init (&buffer); 00582 buffer_grow_str (&buffer, "<osdata type=\"threads\">\n"); 00583 00584 dirp = opendir ("/proc"); 00585 if (dirp) 00586 { 00587 struct dirent *dp; 00588 00589 while ((dp = readdir (dirp)) != NULL) 00590 { 00591 struct stat statbuf; 00592 char procentry[sizeof ("/proc/4294967295")]; 00593 00594 if (!isdigit (dp->d_name[0]) 00595 || NAMELEN (dp) > sizeof ("4294967295") - 1) 00596 continue; 00597 00598 sprintf (procentry, "/proc/%s", dp->d_name); 00599 if (stat (procentry, &statbuf) == 0 00600 && S_ISDIR (statbuf.st_mode)) 00601 { 00602 DIR *dirp2; 00603 char *pathname; 00604 PID_T pid; 00605 char command[32]; 00606 00607 pathname = xstrprintf ("/proc/%s/task", dp->d_name); 00608 00609 pid = atoi (dp->d_name); 00610 command_from_pid (command, sizeof (command), pid); 00611 00612 dirp2 = opendir (pathname); 00613 00614 if (dirp2) 00615 { 00616 struct dirent *dp2; 00617 00618 while ((dp2 = readdir (dirp2)) != NULL) 00619 { 00620 PID_T tid; 00621 int core; 00622 00623 if (!isdigit (dp2->d_name[0]) 00624 || NAMELEN (dp2) > sizeof ("4294967295") - 1) 00625 continue; 00626 00627 tid = atoi (dp2->d_name); 00628 core = linux_common_core_of_thread (ptid_build (pid, tid, 0)); 00629 00630 buffer_xml_printf ( 00631 &buffer, 00632 "<item>" 00633 "<column name=\"pid\">%lld</column>" 00634 "<column name=\"command\">%s</column>" 00635 "<column name=\"tid\">%lld</column>" 00636 "<column name=\"core\">%d</column>" 00637 "</item>", 00638 pid, 00639 command, 00640 tid, 00641 core); 00642 } 00643 00644 closedir (dirp2); 00645 } 00646 00647 xfree (pathname); 00648 } 00649 } 00650 00651 closedir (dirp); 00652 } 00653 00654 buffer_grow_str0 (&buffer, "</osdata>\n"); 00655 buf = buffer_finish (&buffer); 00656 len_avail = strlen (buf); 00657 } 00658 00659 if (offset >= len_avail) 00660 { 00661 /* Done. Get rid of the buffer. */ 00662 buffer_free (&buffer); 00663 buf = NULL; 00664 len_avail = 0; 00665 return 0; 00666 } 00667 00668 if (len > len_avail - offset) 00669 len = len_avail - offset; 00670 memcpy (readbuf, buf + offset, len); 00671 00672 return len; 00673 } 00674 00675 /* Collect all the open file descriptors found in /proc and put the details 00676 found about them into READBUF. */ 00677 00678 static LONGEST 00679 linux_xfer_osdata_fds (gdb_byte *readbuf, 00680 ULONGEST offset, LONGEST len) 00681 { 00682 /* We make the process list snapshot when the object starts to be read. */ 00683 static const char *buf; 00684 static LONGEST len_avail = -1; 00685 static struct buffer buffer; 00686 00687 if (offset == 0) 00688 { 00689 DIR *dirp; 00690 00691 if (len_avail != -1 && len_avail != 0) 00692 buffer_free (&buffer); 00693 len_avail = 0; 00694 buf = NULL; 00695 buffer_init (&buffer); 00696 buffer_grow_str (&buffer, "<osdata type=\"files\">\n"); 00697 00698 dirp = opendir ("/proc"); 00699 if (dirp) 00700 { 00701 struct dirent *dp; 00702 00703 while ((dp = readdir (dirp)) != NULL) 00704 { 00705 struct stat statbuf; 00706 char procentry[sizeof ("/proc/4294967295")]; 00707 00708 if (!isdigit (dp->d_name[0]) 00709 || NAMELEN (dp) > sizeof ("4294967295") - 1) 00710 continue; 00711 00712 sprintf (procentry, "/proc/%s", dp->d_name); 00713 if (stat (procentry, &statbuf) == 0 00714 && S_ISDIR (statbuf.st_mode)) 00715 { 00716 char *pathname; 00717 DIR *dirp2; 00718 PID_T pid; 00719 char command[32]; 00720 00721 pid = atoi (dp->d_name); 00722 command_from_pid (command, sizeof (command), pid); 00723 00724 pathname = xstrprintf ("/proc/%s/fd", dp->d_name); 00725 dirp2 = opendir (pathname); 00726 00727 if (dirp2) 00728 { 00729 struct dirent *dp2; 00730 00731 while ((dp2 = readdir (dirp2)) != NULL) 00732 { 00733 char *fdname; 00734 char buf[1000]; 00735 ssize_t rslt; 00736 00737 if (!isdigit (dp2->d_name[0])) 00738 continue; 00739 00740 fdname = xstrprintf ("%s/%s", pathname, dp2->d_name); 00741 rslt = readlink (fdname, buf, sizeof (buf) - 1); 00742 if (rslt >= 0) 00743 buf[rslt] = '\0'; 00744 00745 buffer_xml_printf ( 00746 &buffer, 00747 "<item>" 00748 "<column name=\"pid\">%s</column>" 00749 "<column name=\"command\">%s</column>" 00750 "<column name=\"file descriptor\">%s</column>" 00751 "<column name=\"name\">%s</column>" 00752 "</item>", 00753 dp->d_name, 00754 command, 00755 dp2->d_name, 00756 (rslt >= 0 ? buf : dp2->d_name)); 00757 } 00758 00759 closedir (dirp2); 00760 } 00761 00762 xfree (pathname); 00763 } 00764 } 00765 00766 closedir (dirp); 00767 } 00768 00769 buffer_grow_str0 (&buffer, "</osdata>\n"); 00770 buf = buffer_finish (&buffer); 00771 len_avail = strlen (buf); 00772 } 00773 00774 if (offset >= len_avail) 00775 { 00776 /* Done. Get rid of the buffer. */ 00777 buffer_free (&buffer); 00778 buf = NULL; 00779 len_avail = 0; 00780 return 0; 00781 } 00782 00783 if (len > len_avail - offset) 00784 len = len_avail - offset; 00785 memcpy (readbuf, buf + offset, len); 00786 00787 return len; 00788 } 00789 00790 /* Returns the socket state STATE in textual form. */ 00791 00792 static const char * 00793 format_socket_state (unsigned char state) 00794 { 00795 /* Copied from include/net/tcp_states.h in the Linux kernel sources. */ 00796 enum { 00797 TCP_ESTABLISHED = 1, 00798 TCP_SYN_SENT, 00799 TCP_SYN_RECV, 00800 TCP_FIN_WAIT1, 00801 TCP_FIN_WAIT2, 00802 TCP_TIME_WAIT, 00803 TCP_CLOSE, 00804 TCP_CLOSE_WAIT, 00805 TCP_LAST_ACK, 00806 TCP_LISTEN, 00807 TCP_CLOSING 00808 }; 00809 00810 switch (state) 00811 { 00812 case TCP_ESTABLISHED: 00813 return "ESTABLISHED"; 00814 case TCP_SYN_SENT: 00815 return "SYN_SENT"; 00816 case TCP_SYN_RECV: 00817 return "SYN_RECV"; 00818 case TCP_FIN_WAIT1: 00819 return "FIN_WAIT1"; 00820 case TCP_FIN_WAIT2: 00821 return "FIN_WAIT2"; 00822 case TCP_TIME_WAIT: 00823 return "TIME_WAIT"; 00824 case TCP_CLOSE: 00825 return "CLOSE"; 00826 case TCP_CLOSE_WAIT: 00827 return "CLOSE_WAIT"; 00828 case TCP_LAST_ACK: 00829 return "LAST_ACK"; 00830 case TCP_LISTEN: 00831 return "LISTEN"; 00832 case TCP_CLOSING: 00833 return "CLOSING"; 00834 default: 00835 return "(unknown)"; 00836 } 00837 } 00838 00839 union socket_addr 00840 { 00841 struct sockaddr sa; 00842 struct sockaddr_in sin; 00843 struct sockaddr_in6 sin6; 00844 }; 00845 00846 /* Auxiliary function used by linux_xfer_osdata_isocket. Formats 00847 information for all open internet sockets of type FAMILY on the 00848 system into BUFFER. If TCP is set, only TCP sockets are processed, 00849 otherwise only UDP sockets are processed. */ 00850 00851 static void 00852 print_sockets (unsigned short family, int tcp, struct buffer *buffer) 00853 { 00854 const char *proc_file; 00855 FILE *fp; 00856 00857 if (family == AF_INET) 00858 proc_file = tcp ? "/proc/net/tcp" : "/proc/net/udp"; 00859 else if (family == AF_INET6) 00860 proc_file = tcp ? "/proc/net/tcp6" : "/proc/net/udp6"; 00861 else 00862 return; 00863 00864 fp = gdb_fopen_cloexec (proc_file, "r"); 00865 if (fp) 00866 { 00867 char buf[8192]; 00868 00869 do 00870 { 00871 if (fgets (buf, sizeof (buf), fp)) 00872 { 00873 uid_t uid; 00874 unsigned long tlen, inode; 00875 int sl, timeout; 00876 unsigned int local_port, remote_port, state; 00877 unsigned int txq, rxq, trun, retn; 00878 char local_address[NI_MAXHOST], remote_address[NI_MAXHOST]; 00879 char extra[512]; 00880 int result; 00881 00882 result = sscanf (buf, 00883 "%d: %33[0-9A-F]:%X %33[0-9A-F]:%X %X %X:%X %X:%lX %X %d %d %lu %512s\n", 00884 &sl, 00885 local_address, &local_port, 00886 remote_address, &remote_port, 00887 &state, 00888 &txq, &rxq, 00889 &trun, &tlen, 00890 &retn, 00891 &uid, 00892 &timeout, 00893 &inode, 00894 extra); 00895 00896 if (result == 15) 00897 { 00898 union socket_addr locaddr, remaddr; 00899 size_t addr_size; 00900 char user[UT_NAMESIZE]; 00901 char local_service[NI_MAXSERV], remote_service[NI_MAXSERV]; 00902 00903 if (family == AF_INET) 00904 { 00905 sscanf (local_address, "%X", 00906 &locaddr.sin.sin_addr.s_addr); 00907 sscanf (remote_address, "%X", 00908 &remaddr.sin.sin_addr.s_addr); 00909 00910 locaddr.sin.sin_port = htons (local_port); 00911 remaddr.sin.sin_port = htons (remote_port); 00912 00913 addr_size = sizeof (struct sockaddr_in); 00914 } 00915 else 00916 { 00917 sscanf (local_address, "%8X%8X%8X%8X", 00918 locaddr.sin6.sin6_addr.s6_addr32, 00919 locaddr.sin6.sin6_addr.s6_addr32 + 1, 00920 locaddr.sin6.sin6_addr.s6_addr32 + 2, 00921 locaddr.sin6.sin6_addr.s6_addr32 + 3); 00922 sscanf (remote_address, "%8X%8X%8X%8X", 00923 remaddr.sin6.sin6_addr.s6_addr32, 00924 remaddr.sin6.sin6_addr.s6_addr32 + 1, 00925 remaddr.sin6.sin6_addr.s6_addr32 + 2, 00926 remaddr.sin6.sin6_addr.s6_addr32 + 3); 00927 00928 locaddr.sin6.sin6_port = htons (local_port); 00929 remaddr.sin6.sin6_port = htons (remote_port); 00930 00931 locaddr.sin6.sin6_flowinfo = 0; 00932 remaddr.sin6.sin6_flowinfo = 0; 00933 locaddr.sin6.sin6_scope_id = 0; 00934 remaddr.sin6.sin6_scope_id = 0; 00935 00936 addr_size = sizeof (struct sockaddr_in6); 00937 } 00938 00939 locaddr.sa.sa_family = remaddr.sa.sa_family = family; 00940 00941 result = getnameinfo (&locaddr.sa, addr_size, 00942 local_address, sizeof (local_address), 00943 local_service, sizeof (local_service), 00944 NI_NUMERICHOST | NI_NUMERICSERV 00945 | (tcp ? 0 : NI_DGRAM)); 00946 if (result) 00947 continue; 00948 00949 result = getnameinfo (&remaddr.sa, addr_size, 00950 remote_address, 00951 sizeof (remote_address), 00952 remote_service, 00953 sizeof (remote_service), 00954 NI_NUMERICHOST | NI_NUMERICSERV 00955 | (tcp ? 0 : NI_DGRAM)); 00956 if (result) 00957 continue; 00958 00959 user_from_uid (user, sizeof (user), uid); 00960 00961 buffer_xml_printf ( 00962 buffer, 00963 "<item>" 00964 "<column name=\"local address\">%s</column>" 00965 "<column name=\"local port\">%s</column>" 00966 "<column name=\"remote address\">%s</column>" 00967 "<column name=\"remote port\">%s</column>" 00968 "<column name=\"state\">%s</column>" 00969 "<column name=\"user\">%s</column>" 00970 "<column name=\"family\">%s</column>" 00971 "<column name=\"protocol\">%s</column>" 00972 "</item>", 00973 local_address, 00974 local_service, 00975 remote_address, 00976 remote_service, 00977 format_socket_state (state), 00978 user, 00979 (family == AF_INET) ? "INET" : "INET6", 00980 tcp ? "STREAM" : "DGRAM"); 00981 } 00982 } 00983 } 00984 while (!feof (fp)); 00985 00986 fclose (fp); 00987 } 00988 } 00989 00990 /* Collect data about internet sockets and write it into READBUF. */ 00991 00992 static LONGEST 00993 linux_xfer_osdata_isockets (gdb_byte *readbuf, 00994 ULONGEST offset, LONGEST len) 00995 { 00996 static const char *buf; 00997 static LONGEST len_avail = -1; 00998 static struct buffer buffer; 00999 01000 if (offset == 0) 01001 { 01002 if (len_avail != -1 && len_avail != 0) 01003 buffer_free (&buffer); 01004 len_avail = 0; 01005 buf = NULL; 01006 buffer_init (&buffer); 01007 buffer_grow_str (&buffer, "<osdata type=\"I sockets\">\n"); 01008 01009 print_sockets (AF_INET, 1, &buffer); 01010 print_sockets (AF_INET, 0, &buffer); 01011 print_sockets (AF_INET6, 1, &buffer); 01012 print_sockets (AF_INET6, 0, &buffer); 01013 01014 buffer_grow_str0 (&buffer, "</osdata>\n"); 01015 buf = buffer_finish (&buffer); 01016 len_avail = strlen (buf); 01017 } 01018 01019 if (offset >= len_avail) 01020 { 01021 /* Done. Get rid of the buffer. */ 01022 buffer_free (&buffer); 01023 buf = NULL; 01024 len_avail = 0; 01025 return 0; 01026 } 01027 01028 if (len > len_avail - offset) 01029 len = len_avail - offset; 01030 memcpy (readbuf, buf + offset, len); 01031 01032 return len; 01033 } 01034 01035 /* Converts the time SECONDS into textual form and copies it into a 01036 buffer TIME, with at most MAXLEN characters copied. */ 01037 01038 static void 01039 time_from_time_t (char *time, int maxlen, TIME_T seconds) 01040 { 01041 if (!seconds) 01042 time[0] = '\0'; 01043 else 01044 { 01045 time_t t = (time_t) seconds; 01046 01047 strncpy (time, ctime (&t), maxlen); 01048 time[maxlen - 1] = '\0'; 01049 } 01050 } 01051 01052 /* Finds the group name for the group GID and copies it into GROUP. 01053 At most MAXLEN characters are copied. */ 01054 01055 static void 01056 group_from_gid (char *group, int maxlen, gid_t gid) 01057 { 01058 struct group *grentry = getgrgid (gid); 01059 01060 if (grentry) 01061 { 01062 strncpy (group, grentry->gr_name, maxlen); 01063 /* Ensure that the group name is null-terminated. */ 01064 group[maxlen - 1] = '\0'; 01065 } 01066 else 01067 group[0] = '\0'; 01068 } 01069 01070 /* Collect data about shared memory recorded in /proc and write it 01071 into READBUF. */ 01072 01073 static LONGEST 01074 linux_xfer_osdata_shm (gdb_byte *readbuf, 01075 ULONGEST offset, LONGEST len) 01076 { 01077 static const char *buf; 01078 static LONGEST len_avail = -1; 01079 static struct buffer buffer; 01080 01081 if (offset == 0) 01082 { 01083 FILE *fp; 01084 01085 if (len_avail != -1 && len_avail != 0) 01086 buffer_free (&buffer); 01087 len_avail = 0; 01088 buf = NULL; 01089 buffer_init (&buffer); 01090 buffer_grow_str (&buffer, "<osdata type=\"shared memory\">\n"); 01091 01092 fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r"); 01093 if (fp) 01094 { 01095 char buf[8192]; 01096 01097 do 01098 { 01099 if (fgets (buf, sizeof (buf), fp)) 01100 { 01101 key_t key; 01102 uid_t uid, cuid; 01103 gid_t gid, cgid; 01104 PID_T cpid, lpid; 01105 int shmid, size, nattch; 01106 TIME_T atime, dtime, ctime; 01107 unsigned int perms; 01108 int items_read; 01109 01110 items_read = sscanf (buf, 01111 "%d %d %o %d %lld %lld %d %u %u %u %u %lld %lld %lld", 01112 &key, &shmid, &perms, &size, 01113 &cpid, &lpid, 01114 &nattch, 01115 &uid, &gid, &cuid, &cgid, 01116 &atime, &dtime, &ctime); 01117 01118 if (items_read == 14) 01119 { 01120 char user[UT_NAMESIZE], group[UT_NAMESIZE]; 01121 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE]; 01122 char ccmd[32], lcmd[32]; 01123 char atime_str[32], dtime_str[32], ctime_str[32]; 01124 01125 user_from_uid (user, sizeof (user), uid); 01126 group_from_gid (group, sizeof (group), gid); 01127 user_from_uid (cuser, sizeof (cuser), cuid); 01128 group_from_gid (cgroup, sizeof (cgroup), cgid); 01129 01130 command_from_pid (ccmd, sizeof (ccmd), cpid); 01131 command_from_pid (lcmd, sizeof (lcmd), lpid); 01132 01133 time_from_time_t (atime_str, sizeof (atime_str), atime); 01134 time_from_time_t (dtime_str, sizeof (dtime_str), dtime); 01135 time_from_time_t (ctime_str, sizeof (ctime_str), ctime); 01136 01137 buffer_xml_printf ( 01138 &buffer, 01139 "<item>" 01140 "<column name=\"key\">%d</column>" 01141 "<column name=\"shmid\">%d</column>" 01142 "<column name=\"permissions\">%o</column>" 01143 "<column name=\"size\">%d</column>" 01144 "<column name=\"creator command\">%s</column>" 01145 "<column name=\"last op. command\">%s</column>" 01146 "<column name=\"num attached\">%d</column>" 01147 "<column name=\"user\">%s</column>" 01148 "<column name=\"group\">%s</column>" 01149 "<column name=\"creator user\">%s</column>" 01150 "<column name=\"creator group\">%s</column>" 01151 "<column name=\"last shmat() time\">%s</column>" 01152 "<column name=\"last shmdt() time\">%s</column>" 01153 "<column name=\"last shmctl() time\">%s</column>" 01154 "</item>", 01155 key, 01156 shmid, 01157 perms, 01158 size, 01159 ccmd, 01160 lcmd, 01161 nattch, 01162 user, 01163 group, 01164 cuser, 01165 cgroup, 01166 atime_str, 01167 dtime_str, 01168 ctime_str); 01169 } 01170 } 01171 } 01172 while (!feof (fp)); 01173 01174 fclose (fp); 01175 } 01176 01177 buffer_grow_str0 (&buffer, "</osdata>\n"); 01178 buf = buffer_finish (&buffer); 01179 len_avail = strlen (buf); 01180 } 01181 01182 if (offset >= len_avail) 01183 { 01184 /* Done. Get rid of the buffer. */ 01185 buffer_free (&buffer); 01186 buf = NULL; 01187 len_avail = 0; 01188 return 0; 01189 } 01190 01191 if (len > len_avail - offset) 01192 len = len_avail - offset; 01193 memcpy (readbuf, buf + offset, len); 01194 01195 return len; 01196 } 01197 01198 /* Collect data about semaphores recorded in /proc and write it 01199 into READBUF. */ 01200 01201 static LONGEST 01202 linux_xfer_osdata_sem (gdb_byte *readbuf, 01203 ULONGEST offset, LONGEST len) 01204 { 01205 static const char *buf; 01206 static LONGEST len_avail = -1; 01207 static struct buffer buffer; 01208 01209 if (offset == 0) 01210 { 01211 FILE *fp; 01212 01213 if (len_avail != -1 && len_avail != 0) 01214 buffer_free (&buffer); 01215 len_avail = 0; 01216 buf = NULL; 01217 buffer_init (&buffer); 01218 buffer_grow_str (&buffer, "<osdata type=\"semaphores\">\n"); 01219 01220 fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r"); 01221 if (fp) 01222 { 01223 char buf[8192]; 01224 01225 do 01226 { 01227 if (fgets (buf, sizeof (buf), fp)) 01228 { 01229 key_t key; 01230 uid_t uid, cuid; 01231 gid_t gid, cgid; 01232 unsigned int perms, nsems; 01233 int semid; 01234 TIME_T otime, ctime; 01235 int items_read; 01236 01237 items_read = sscanf (buf, 01238 "%d %d %o %u %d %d %d %d %lld %lld", 01239 &key, &semid, &perms, &nsems, 01240 &uid, &gid, &cuid, &cgid, 01241 &otime, &ctime); 01242 01243 if (items_read == 10) 01244 { 01245 char user[UT_NAMESIZE], group[UT_NAMESIZE]; 01246 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE]; 01247 char otime_str[32], ctime_str[32]; 01248 01249 user_from_uid (user, sizeof (user), uid); 01250 group_from_gid (group, sizeof (group), gid); 01251 user_from_uid (cuser, sizeof (cuser), cuid); 01252 group_from_gid (cgroup, sizeof (cgroup), cgid); 01253 01254 time_from_time_t (otime_str, sizeof (otime_str), otime); 01255 time_from_time_t (ctime_str, sizeof (ctime_str), ctime); 01256 01257 buffer_xml_printf ( 01258 &buffer, 01259 "<item>" 01260 "<column name=\"key\">%d</column>" 01261 "<column name=\"semid\">%d</column>" 01262 "<column name=\"permissions\">%o</column>" 01263 "<column name=\"num semaphores\">%u</column>" 01264 "<column name=\"user\">%s</column>" 01265 "<column name=\"group\">%s</column>" 01266 "<column name=\"creator user\">%s</column>" 01267 "<column name=\"creator group\">%s</column>" 01268 "<column name=\"last semop() time\">%s</column>" 01269 "<column name=\"last semctl() time\">%s</column>" 01270 "</item>", 01271 key, 01272 semid, 01273 perms, 01274 nsems, 01275 user, 01276 group, 01277 cuser, 01278 cgroup, 01279 otime_str, 01280 ctime_str); 01281 } 01282 } 01283 } 01284 while (!feof (fp)); 01285 01286 fclose (fp); 01287 } 01288 01289 buffer_grow_str0 (&buffer, "</osdata>\n"); 01290 buf = buffer_finish (&buffer); 01291 len_avail = strlen (buf); 01292 } 01293 01294 if (offset >= len_avail) 01295 { 01296 /* Done. Get rid of the buffer. */ 01297 buffer_free (&buffer); 01298 buf = NULL; 01299 len_avail = 0; 01300 return 0; 01301 } 01302 01303 if (len > len_avail - offset) 01304 len = len_avail - offset; 01305 memcpy (readbuf, buf + offset, len); 01306 01307 return len; 01308 } 01309 01310 /* Collect data about message queues recorded in /proc and write it 01311 into READBUF. */ 01312 01313 static LONGEST 01314 linux_xfer_osdata_msg (gdb_byte *readbuf, 01315 ULONGEST offset, LONGEST len) 01316 { 01317 static const char *buf; 01318 static LONGEST len_avail = -1; 01319 static struct buffer buffer; 01320 01321 if (offset == 0) 01322 { 01323 FILE *fp; 01324 01325 if (len_avail != -1 && len_avail != 0) 01326 buffer_free (&buffer); 01327 len_avail = 0; 01328 buf = NULL; 01329 buffer_init (&buffer); 01330 buffer_grow_str (&buffer, "<osdata type=\"message queues\">\n"); 01331 01332 fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r"); 01333 if (fp) 01334 { 01335 char buf[8192]; 01336 01337 do 01338 { 01339 if (fgets (buf, sizeof (buf), fp)) 01340 { 01341 key_t key; 01342 PID_T lspid, lrpid; 01343 uid_t uid, cuid; 01344 gid_t gid, cgid; 01345 unsigned int perms, cbytes, qnum; 01346 int msqid; 01347 TIME_T stime, rtime, ctime; 01348 int items_read; 01349 01350 items_read = sscanf (buf, 01351 "%d %d %o %u %u %lld %lld %d %d %d %d %lld %lld %lld", 01352 &key, &msqid, &perms, &cbytes, &qnum, 01353 &lspid, &lrpid, &uid, &gid, &cuid, &cgid, 01354 &stime, &rtime, &ctime); 01355 01356 if (items_read == 14) 01357 { 01358 char user[UT_NAMESIZE], group[UT_NAMESIZE]; 01359 char cuser[UT_NAMESIZE], cgroup[UT_NAMESIZE]; 01360 char lscmd[32], lrcmd[32]; 01361 char stime_str[32], rtime_str[32], ctime_str[32]; 01362 01363 user_from_uid (user, sizeof (user), uid); 01364 group_from_gid (group, sizeof (group), gid); 01365 user_from_uid (cuser, sizeof (cuser), cuid); 01366 group_from_gid (cgroup, sizeof (cgroup), cgid); 01367 01368 command_from_pid (lscmd, sizeof (lscmd), lspid); 01369 command_from_pid (lrcmd, sizeof (lrcmd), lrpid); 01370 01371 time_from_time_t (stime_str, sizeof (stime_str), stime); 01372 time_from_time_t (rtime_str, sizeof (rtime_str), rtime); 01373 time_from_time_t (ctime_str, sizeof (ctime_str), ctime); 01374 01375 buffer_xml_printf ( 01376 &buffer, 01377 "<item>" 01378 "<column name=\"key\">%d</column>" 01379 "<column name=\"msqid\">%d</column>" 01380 "<column name=\"permissions\">%o</column>" 01381 "<column name=\"num used bytes\">%u</column>" 01382 "<column name=\"num messages\">%u</column>" 01383 "<column name=\"last msgsnd() command\">%s</column>" 01384 "<column name=\"last msgrcv() command\">%s</column>" 01385 "<column name=\"user\">%s</column>" 01386 "<column name=\"group\">%s</column>" 01387 "<column name=\"creator user\">%s</column>" 01388 "<column name=\"creator group\">%s</column>" 01389 "<column name=\"last msgsnd() time\">%s</column>" 01390 "<column name=\"last msgrcv() time\">%s</column>" 01391 "<column name=\"last msgctl() time\">%s</column>" 01392 "</item>", 01393 key, 01394 msqid, 01395 perms, 01396 cbytes, 01397 qnum, 01398 lscmd, 01399 lrcmd, 01400 user, 01401 group, 01402 cuser, 01403 cgroup, 01404 stime_str, 01405 rtime_str, 01406 ctime_str); 01407 } 01408 } 01409 } 01410 while (!feof (fp)); 01411 01412 fclose (fp); 01413 } 01414 01415 buffer_grow_str0 (&buffer, "</osdata>\n"); 01416 buf = buffer_finish (&buffer); 01417 len_avail = strlen (buf); 01418 } 01419 01420 if (offset >= len_avail) 01421 { 01422 /* Done. Get rid of the buffer. */ 01423 buffer_free (&buffer); 01424 buf = NULL; 01425 len_avail = 0; 01426 return 0; 01427 } 01428 01429 if (len > len_avail - offset) 01430 len = len_avail - offset; 01431 memcpy (readbuf, buf + offset, len); 01432 01433 return len; 01434 } 01435 01436 /* Collect data about loaded kernel modules and write it into 01437 READBUF. */ 01438 01439 static LONGEST 01440 linux_xfer_osdata_modules (gdb_byte *readbuf, 01441 ULONGEST offset, LONGEST len) 01442 { 01443 static const char *buf; 01444 static LONGEST len_avail = -1; 01445 static struct buffer buffer; 01446 01447 if (offset == 0) 01448 { 01449 FILE *fp; 01450 01451 if (len_avail != -1 && len_avail != 0) 01452 buffer_free (&buffer); 01453 len_avail = 0; 01454 buf = NULL; 01455 buffer_init (&buffer); 01456 buffer_grow_str (&buffer, "<osdata type=\"modules\">\n"); 01457 01458 fp = gdb_fopen_cloexec ("/proc/modules", "r"); 01459 if (fp) 01460 { 01461 char buf[8192]; 01462 01463 do 01464 { 01465 if (fgets (buf, sizeof (buf), fp)) 01466 { 01467 char name[64], dependencies[256], status[16]; 01468 unsigned int size; 01469 unsigned long long address; 01470 int uses; 01471 int items_read; 01472 01473 items_read = sscanf (buf, 01474 "%64s %d %d %256s %16s 0x%llx", 01475 name, &size, &uses, 01476 dependencies, status, &address); 01477 01478 if (items_read == 6) 01479 buffer_xml_printf ( 01480 &buffer, 01481 "<item>" 01482 "<column name=\"name\">%s</column>" 01483 "<column name=\"size\">%u</column>" 01484 "<column name=\"num uses\">%d</column>" 01485 "<column name=\"dependencies\">%s</column>" 01486 "<column name=\"status\">%s</column>" 01487 "<column name=\"address\">%llx</column>" 01488 "</item>", 01489 name, 01490 size, 01491 uses, 01492 dependencies, 01493 status, 01494 address); 01495 } 01496 } 01497 while (!feof (fp)); 01498 01499 fclose (fp); 01500 } 01501 01502 buffer_grow_str0 (&buffer, "</osdata>\n"); 01503 buf = buffer_finish (&buffer); 01504 len_avail = strlen (buf); 01505 } 01506 01507 if (offset >= len_avail) 01508 { 01509 /* Done. Get rid of the buffer. */ 01510 buffer_free (&buffer); 01511 buf = NULL; 01512 len_avail = 0; 01513 return 0; 01514 } 01515 01516 if (len > len_avail - offset) 01517 len = len_avail - offset; 01518 memcpy (readbuf, buf + offset, len); 01519 01520 return len; 01521 } 01522 01523 struct osdata_type { 01524 char *type; 01525 char *title; 01526 char *description; 01527 LONGEST (*getter) (gdb_byte *readbuf, ULONGEST offset, LONGEST len); 01528 } osdata_table[] = { 01529 { "processes", "Processes", "Listing of all processes", 01530 linux_xfer_osdata_processes }, 01531 { "procgroups", "Process groups", "Listing of all process groups", 01532 linux_xfer_osdata_processgroups }, 01533 { "threads", "Threads", "Listing of all threads", 01534 linux_xfer_osdata_threads }, 01535 { "files", "File descriptors", "Listing of all file descriptors", 01536 linux_xfer_osdata_fds }, 01537 { "sockets", "Sockets", "Listing of all internet-domain sockets", 01538 linux_xfer_osdata_isockets }, 01539 { "shm", "Shared-memory regions", "Listing of all shared-memory regions", 01540 linux_xfer_osdata_shm }, 01541 { "semaphores", "Semaphores", "Listing of all semaphores", 01542 linux_xfer_osdata_sem }, 01543 { "msg", "Message queues", "Listing of all message queues", 01544 linux_xfer_osdata_msg }, 01545 { "modules", "Kernel modules", "Listing of all loaded kernel modules", 01546 linux_xfer_osdata_modules }, 01547 { NULL, NULL, NULL } 01548 }; 01549 01550 LONGEST 01551 linux_common_xfer_osdata (const char *annex, gdb_byte *readbuf, 01552 ULONGEST offset, LONGEST len) 01553 { 01554 if (!annex || *annex == '\0') 01555 { 01556 static const char *buf; 01557 static LONGEST len_avail = -1; 01558 static struct buffer buffer; 01559 01560 if (offset == 0) 01561 { 01562 int i; 01563 01564 if (len_avail != -1 && len_avail != 0) 01565 buffer_free (&buffer); 01566 len_avail = 0; 01567 buf = NULL; 01568 buffer_init (&buffer); 01569 buffer_grow_str (&buffer, "<osdata type=\"types\">\n"); 01570 01571 for (i = 0; osdata_table[i].type; ++i) 01572 buffer_xml_printf ( 01573 &buffer, 01574 "<item>" 01575 "<column name=\"Type\">%s</column>" 01576 "<column name=\"Description\">%s</column>" 01577 "<column name=\"Title\">%s</column>" 01578 "</item>", 01579 osdata_table[i].type, 01580 osdata_table[i].description, 01581 osdata_table[i].title); 01582 01583 buffer_grow_str0 (&buffer, "</osdata>\n"); 01584 buf = buffer_finish (&buffer); 01585 len_avail = strlen (buf); 01586 } 01587 01588 if (offset >= len_avail) 01589 { 01590 /* Done. Get rid of the buffer. */ 01591 buffer_free (&buffer); 01592 buf = NULL; 01593 len_avail = 0; 01594 return 0; 01595 } 01596 01597 if (len > len_avail - offset) 01598 len = len_avail - offset; 01599 memcpy (readbuf, buf + offset, len); 01600 01601 return len; 01602 } 01603 else 01604 { 01605 int i; 01606 01607 for (i = 0; osdata_table[i].type; ++i) 01608 { 01609 if (strcmp (annex, osdata_table[i].type) == 0) 01610 { 01611 gdb_assert (readbuf); 01612 01613 return (osdata_table[i].getter) (readbuf, offset, len); 01614 } 01615 } 01616 01617 return 0; 01618 } 01619 } 01620