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