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