2004-08-10 Michael Chastain <mec.gnu@mindspring.com>
[deliverable/binutils-gdb.git] / gdb / linux-proc.c
1 /* GNU/Linux specific methods for using the /proc file system.
2
3 Copyright 2001, 2002 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 2 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, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include "defs.h"
23 #include "inferior.h"
24 #include <sys/param.h> /* for MAXPATHLEN */
25 #include <sys/procfs.h> /* for elf_gregset etc. */
26 #include "gdb_stat.h" /* for struct stat */
27 #include <ctype.h> /* for isdigit */
28 #include <unistd.h> /* for open, pread64 */
29 #include <fcntl.h> /* for O_RDONLY */
30 #include "regcache.h" /* for registers_changed */
31 #include "gregset.h" /* for gregset */
32 #include "gdbcore.h" /* for get_exec_file */
33 #include "gdbthread.h" /* for struct thread_info etc. */
34 #include "elf-bfd.h" /* for elfcore_write_* */
35 #include "cli/cli-decode.h" /* for add_info */
36 #include "gdb_string.h"
37
38 #include <signal.h>
39
40 #include "linux-nat.h"
41
42 #ifndef O_LARGEFILE
43 #define O_LARGEFILE 0
44 #endif
45
46 /* Function: child_pid_to_exec_file
47 *
48 * Accepts an integer pid
49 * Returns a string representing a file that can be opened
50 * to get the symbols for the child process.
51 */
52
53 char *
54 child_pid_to_exec_file (int pid)
55 {
56 char *name1, *name2;
57
58 name1 = xmalloc (MAXPATHLEN);
59 name2 = xmalloc (MAXPATHLEN);
60 make_cleanup (xfree, name1);
61 make_cleanup (xfree, name2);
62 memset (name2, 0, MAXPATHLEN);
63
64 sprintf (name1, "/proc/%d/exe", pid);
65 if (readlink (name1, name2, MAXPATHLEN) > 0)
66 return name2;
67 else
68 return name1;
69 }
70
71 /* Function: read_mappings
72 *
73 * Service function for corefiles and info proc.
74 */
75
76 static int
77 read_mapping (FILE *mapfile,
78 long long *addr,
79 long long *endaddr,
80 char *permissions,
81 long long *offset,
82 char *device, long long *inode, char *filename)
83 {
84 int ret = fscanf (mapfile, "%llx-%llx %s %llx %s %llx",
85 addr, endaddr, permissions, offset, device, inode);
86
87 if (ret > 0 && ret != EOF && *inode != 0)
88 {
89 /* Eat everything up to EOL for the filename. This will prevent
90 weird filenames (such as one with embedded whitespace) from
91 confusing this code. It also makes this code more robust
92 in respect to annotations the kernel may add after the
93 filename.
94
95 Note the filename is used for informational purposes only. */
96 ret += fscanf (mapfile, "%[^\n]\n", filename);
97 }
98 else
99 {
100 filename[0] = '\0'; /* no filename */
101 fscanf (mapfile, "\n");
102 }
103 return (ret != 0 && ret != EOF);
104 }
105
106 /* Function: linux_find_memory_regions
107 *
108 * Fills the "to_find_memory_regions" target vector.
109 * Lists the memory regions in the inferior for a corefile.
110 */
111
112 static int
113 linux_find_memory_regions (int (*func) (CORE_ADDR,
114 unsigned long,
115 int, int, int, void *), void *obfd)
116 {
117 long long pid = PIDGET (inferior_ptid);
118 char mapsfilename[MAXPATHLEN];
119 FILE *mapsfile;
120 long long addr, endaddr, size, offset, inode;
121 char permissions[8], device[8], filename[MAXPATHLEN];
122 int read, write, exec;
123 int ret;
124
125 /* Compose the filename for the /proc memory map, and open it. */
126 sprintf (mapsfilename, "/proc/%lld/maps", pid);
127 if ((mapsfile = fopen (mapsfilename, "r")) == NULL)
128 error ("Could not open %s\n", mapsfilename);
129
130 if (info_verbose)
131 fprintf_filtered (gdb_stdout,
132 "Reading memory regions from %s\n", mapsfilename);
133
134 /* Now iterate until end-of-file. */
135 while (read_mapping (mapsfile, &addr, &endaddr, &permissions[0],
136 &offset, &device[0], &inode, &filename[0]))
137 {
138 size = endaddr - addr;
139
140 /* Get the segment's permissions. */
141 read = (strchr (permissions, 'r') != 0);
142 write = (strchr (permissions, 'w') != 0);
143 exec = (strchr (permissions, 'x') != 0);
144
145 if (info_verbose)
146 {
147 fprintf_filtered (gdb_stdout,
148 "Save segment, %lld bytes at 0x%s (%c%c%c)",
149 size, paddr_nz (addr),
150 read ? 'r' : ' ',
151 write ? 'w' : ' ', exec ? 'x' : ' ');
152 if (filename && filename[0])
153 fprintf_filtered (gdb_stdout, " for %s", filename);
154 fprintf_filtered (gdb_stdout, "\n");
155 }
156
157 /* Invoke the callback function to create the corefile segment. */
158 func (addr, size, read, write, exec, obfd);
159 }
160 fclose (mapsfile);
161 return 0;
162 }
163
164 /* Function: linux_do_thread_registers
165 *
166 * Records the thread's register state for the corefile note section.
167 */
168
169 static char *
170 linux_do_thread_registers (bfd *obfd, ptid_t ptid,
171 char *note_data, int *note_size)
172 {
173 gdb_gregset_t gregs;
174 gdb_fpregset_t fpregs;
175 #ifdef FILL_FPXREGSET
176 gdb_fpxregset_t fpxregs;
177 #endif
178 unsigned long lwp = ptid_get_lwp (ptid);
179
180 fill_gregset (&gregs, -1);
181 note_data = (char *) elfcore_write_prstatus (obfd,
182 note_data,
183 note_size,
184 lwp,
185 stop_signal, &gregs);
186
187 fill_fpregset (&fpregs, -1);
188 note_data = (char *) elfcore_write_prfpreg (obfd,
189 note_data,
190 note_size,
191 &fpregs, sizeof (fpregs));
192 #ifdef FILL_FPXREGSET
193 fill_fpxregset (&fpxregs, -1);
194 note_data = (char *) elfcore_write_prxfpreg (obfd,
195 note_data,
196 note_size,
197 &fpxregs, sizeof (fpxregs));
198 #endif
199 return note_data;
200 }
201
202 struct linux_corefile_thread_data
203 {
204 bfd *obfd;
205 char *note_data;
206 int *note_size;
207 int num_notes;
208 };
209
210 /* Function: linux_corefile_thread_callback
211 *
212 * Called by gdbthread.c once per thread.
213 * Records the thread's register state for the corefile note section.
214 */
215
216 static int
217 linux_corefile_thread_callback (struct lwp_info *ti, void *data)
218 {
219 struct linux_corefile_thread_data *args = data;
220 ptid_t saved_ptid = inferior_ptid;
221
222 inferior_ptid = ti->ptid;
223 registers_changed ();
224 target_fetch_registers (-1); /* FIXME should not be necessary;
225 fill_gregset should do it automatically. */
226 args->note_data = linux_do_thread_registers (args->obfd,
227 ti->ptid,
228 args->note_data,
229 args->note_size);
230 args->num_notes++;
231 inferior_ptid = saved_ptid;
232 registers_changed ();
233 target_fetch_registers (-1); /* FIXME should not be necessary;
234 fill_gregset should do it automatically. */
235 return 0;
236 }
237
238 /* Function: linux_do_registers
239 *
240 * Records the register state for the corefile note section.
241 */
242
243 static char *
244 linux_do_registers (bfd *obfd, ptid_t ptid,
245 char *note_data, int *note_size)
246 {
247 registers_changed ();
248 target_fetch_registers (-1); /* FIXME should not be necessary;
249 fill_gregset should do it automatically. */
250 return linux_do_thread_registers (obfd,
251 ptid_build (ptid_get_pid (inferior_ptid),
252 ptid_get_pid (inferior_ptid),
253 0),
254 note_data, note_size);
255 return note_data;
256 }
257
258 /* Function: linux_make_note_section
259 *
260 * Fills the "to_make_corefile_note" target vector.
261 * Builds the note section for a corefile, and returns it
262 * in a malloc buffer.
263 */
264
265 static char *
266 linux_make_note_section (bfd *obfd, int *note_size)
267 {
268 struct linux_corefile_thread_data thread_args;
269 struct cleanup *old_chain;
270 char fname[16] = { '\0' };
271 char psargs[80] = { '\0' };
272 char *note_data = NULL;
273 ptid_t current_ptid = inferior_ptid;
274 char *auxv;
275 int auxv_len;
276
277 if (get_exec_file (0))
278 {
279 strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
280 strncpy (psargs, get_exec_file (0), sizeof (psargs));
281 if (get_inferior_args ())
282 {
283 strncat (psargs, " ", sizeof (psargs) - strlen (psargs));
284 strncat (psargs, get_inferior_args (),
285 sizeof (psargs) - strlen (psargs));
286 }
287 note_data = (char *) elfcore_write_prpsinfo (obfd,
288 note_data,
289 note_size, fname, psargs);
290 }
291
292 /* Dump information for threads. */
293 thread_args.obfd = obfd;
294 thread_args.note_data = note_data;
295 thread_args.note_size = note_size;
296 thread_args.num_notes = 0;
297 iterate_over_lwps (linux_corefile_thread_callback, &thread_args);
298 if (thread_args.num_notes == 0)
299 {
300 /* iterate_over_threads didn't come up with any threads;
301 just use inferior_ptid. */
302 note_data = linux_do_registers (obfd, inferior_ptid,
303 note_data, note_size);
304 }
305 else
306 {
307 note_data = thread_args.note_data;
308 }
309
310 auxv_len = target_auxv_read (&current_target, &auxv);
311 if (auxv_len > 0)
312 {
313 note_data = elfcore_write_note (obfd, note_data, note_size,
314 "CORE", NT_AUXV, auxv, auxv_len);
315 xfree (auxv);
316 }
317
318 make_cleanup (xfree, note_data);
319 return note_data;
320 }
321
322 /*
323 * Function: linux_info_proc_cmd
324 *
325 * Implement the "info proc" command.
326 */
327
328 static void
329 linux_info_proc_cmd (char *args, int from_tty)
330 {
331 long long pid = PIDGET (inferior_ptid);
332 FILE *procfile;
333 char **argv = NULL;
334 char buffer[MAXPATHLEN];
335 char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
336 int cmdline_f = 1;
337 int cwd_f = 1;
338 int exe_f = 1;
339 int mappings_f = 0;
340 int environ_f = 0;
341 int status_f = 0;
342 int stat_f = 0;
343 int all = 0;
344 struct stat dummy;
345
346 if (args)
347 {
348 /* Break up 'args' into an argv array. */
349 if ((argv = buildargv (args)) == NULL)
350 nomem (0);
351 else
352 make_cleanup_freeargv (argv);
353 }
354 while (argv != NULL && *argv != NULL)
355 {
356 if (isdigit (argv[0][0]))
357 {
358 pid = strtoul (argv[0], NULL, 10);
359 }
360 else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
361 {
362 mappings_f = 1;
363 }
364 else if (strcmp (argv[0], "status") == 0)
365 {
366 status_f = 1;
367 }
368 else if (strcmp (argv[0], "stat") == 0)
369 {
370 stat_f = 1;
371 }
372 else if (strcmp (argv[0], "cmd") == 0)
373 {
374 cmdline_f = 1;
375 }
376 else if (strncmp (argv[0], "exe", strlen (argv[0])) == 0)
377 {
378 exe_f = 1;
379 }
380 else if (strcmp (argv[0], "cwd") == 0)
381 {
382 cwd_f = 1;
383 }
384 else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
385 {
386 all = 1;
387 }
388 else
389 {
390 /* [...] (future options here) */
391 }
392 argv++;
393 }
394 if (pid == 0)
395 error ("No current process: you must name one.");
396
397 sprintf (fname1, "/proc/%lld", pid);
398 if (stat (fname1, &dummy) != 0)
399 error ("No /proc directory: '%s'", fname1);
400
401 printf_filtered ("process %lld\n", pid);
402 if (cmdline_f || all)
403 {
404 sprintf (fname1, "/proc/%lld/cmdline", pid);
405 if ((procfile = fopen (fname1, "r")) > 0)
406 {
407 fgets (buffer, sizeof (buffer), procfile);
408 printf_filtered ("cmdline = '%s'\n", buffer);
409 fclose (procfile);
410 }
411 else
412 warning ("unable to open /proc file '%s'", fname1);
413 }
414 if (cwd_f || all)
415 {
416 sprintf (fname1, "/proc/%lld/cwd", pid);
417 memset (fname2, 0, sizeof (fname2));
418 if (readlink (fname1, fname2, sizeof (fname2)) > 0)
419 printf_filtered ("cwd = '%s'\n", fname2);
420 else
421 warning ("unable to read link '%s'", fname1);
422 }
423 if (exe_f || all)
424 {
425 sprintf (fname1, "/proc/%lld/exe", pid);
426 memset (fname2, 0, sizeof (fname2));
427 if (readlink (fname1, fname2, sizeof (fname2)) > 0)
428 printf_filtered ("exe = '%s'\n", fname2);
429 else
430 warning ("unable to read link '%s'", fname1);
431 }
432 if (mappings_f || all)
433 {
434 sprintf (fname1, "/proc/%lld/maps", pid);
435 if ((procfile = fopen (fname1, "r")) > 0)
436 {
437 long long addr, endaddr, size, offset, inode;
438 char permissions[8], device[8], filename[MAXPATHLEN];
439
440 printf_filtered ("Mapped address spaces:\n\n");
441 if (TARGET_ADDR_BIT == 32)
442 {
443 printf_filtered ("\t%10s %10s %10s %10s %7s\n",
444 "Start Addr",
445 " End Addr",
446 " Size", " Offset", "objfile");
447 }
448 else
449 {
450 printf_filtered (" %18s %18s %10s %10s %7s\n",
451 "Start Addr",
452 " End Addr",
453 " Size", " Offset", "objfile");
454 }
455
456 while (read_mapping (procfile, &addr, &endaddr, &permissions[0],
457 &offset, &device[0], &inode, &filename[0]))
458 {
459 size = endaddr - addr;
460
461 /* FIXME: carlton/2003-08-27: Maybe the printf_filtered
462 calls here (and possibly above) should be abstracted
463 out into their own functions? Andrew suggests using
464 a generic local_address_string instead to print out
465 the addresses; that makes sense to me, too. */
466
467 if (TARGET_ADDR_BIT == 32)
468 {
469 printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
470 (unsigned long) addr, /* FIXME: pr_addr */
471 (unsigned long) endaddr,
472 (int) size,
473 (unsigned int) offset,
474 filename[0] ? filename : "");
475 }
476 else
477 {
478 printf_filtered (" %#18lx %#18lx %#10x %#10x %7s\n",
479 (unsigned long) addr, /* FIXME: pr_addr */
480 (unsigned long) endaddr,
481 (int) size,
482 (unsigned int) offset,
483 filename[0] ? filename : "");
484 }
485 }
486
487 fclose (procfile);
488 }
489 else
490 warning ("unable to open /proc file '%s'", fname1);
491 }
492 if (status_f || all)
493 {
494 sprintf (fname1, "/proc/%lld/status", pid);
495 if ((procfile = fopen (fname1, "r")) > 0)
496 {
497 while (fgets (buffer, sizeof (buffer), procfile) != NULL)
498 puts_filtered (buffer);
499 fclose (procfile);
500 }
501 else
502 warning ("unable to open /proc file '%s'", fname1);
503 }
504 if (stat_f || all)
505 {
506 sprintf (fname1, "/proc/%lld/stat", pid);
507 if ((procfile = fopen (fname1, "r")) > 0)
508 {
509 int itmp;
510 char ctmp;
511
512 if (fscanf (procfile, "%d ", &itmp) > 0)
513 printf_filtered ("Process: %d\n", itmp);
514 if (fscanf (procfile, "%s ", &buffer[0]) > 0)
515 printf_filtered ("Exec file: %s\n", buffer);
516 if (fscanf (procfile, "%c ", &ctmp) > 0)
517 printf_filtered ("State: %c\n", ctmp);
518 if (fscanf (procfile, "%d ", &itmp) > 0)
519 printf_filtered ("Parent process: %d\n", itmp);
520 if (fscanf (procfile, "%d ", &itmp) > 0)
521 printf_filtered ("Process group: %d\n", itmp);
522 if (fscanf (procfile, "%d ", &itmp) > 0)
523 printf_filtered ("Session id: %d\n", itmp);
524 if (fscanf (procfile, "%d ", &itmp) > 0)
525 printf_filtered ("TTY: %d\n", itmp);
526 if (fscanf (procfile, "%d ", &itmp) > 0)
527 printf_filtered ("TTY owner process group: %d\n", itmp);
528 if (fscanf (procfile, "%u ", &itmp) > 0)
529 printf_filtered ("Flags: 0x%x\n", itmp);
530 if (fscanf (procfile, "%u ", &itmp) > 0)
531 printf_filtered ("Minor faults (no memory page): %u\n",
532 (unsigned int) itmp);
533 if (fscanf (procfile, "%u ", &itmp) > 0)
534 printf_filtered ("Minor faults, children: %u\n",
535 (unsigned int) itmp);
536 if (fscanf (procfile, "%u ", &itmp) > 0)
537 printf_filtered ("Major faults (memory page faults): %u\n",
538 (unsigned int) itmp);
539 if (fscanf (procfile, "%u ", &itmp) > 0)
540 printf_filtered ("Major faults, children: %u\n",
541 (unsigned int) itmp);
542 if (fscanf (procfile, "%d ", &itmp) > 0)
543 printf_filtered ("utime: %d\n", itmp);
544 if (fscanf (procfile, "%d ", &itmp) > 0)
545 printf_filtered ("stime: %d\n", itmp);
546 if (fscanf (procfile, "%d ", &itmp) > 0)
547 printf_filtered ("utime, children: %d\n", itmp);
548 if (fscanf (procfile, "%d ", &itmp) > 0)
549 printf_filtered ("stime, children: %d\n", itmp);
550 if (fscanf (procfile, "%d ", &itmp) > 0)
551 printf_filtered ("jiffies remaining in current time slice: %d\n",
552 itmp);
553 if (fscanf (procfile, "%d ", &itmp) > 0)
554 printf_filtered ("'nice' value: %d\n", itmp);
555 if (fscanf (procfile, "%u ", &itmp) > 0)
556 printf_filtered ("jiffies until next timeout: %u\n",
557 (unsigned int) itmp);
558 if (fscanf (procfile, "%u ", &itmp) > 0)
559 printf_filtered ("jiffies until next SIGALRM: %u\n",
560 (unsigned int) itmp);
561 if (fscanf (procfile, "%d ", &itmp) > 0)
562 printf_filtered ("start time (jiffies since system boot): %d\n",
563 itmp);
564 if (fscanf (procfile, "%u ", &itmp) > 0)
565 printf_filtered ("Virtual memory size: %u\n",
566 (unsigned int) itmp);
567 if (fscanf (procfile, "%u ", &itmp) > 0)
568 printf_filtered ("Resident set size: %u\n", (unsigned int) itmp);
569 if (fscanf (procfile, "%u ", &itmp) > 0)
570 printf_filtered ("rlim: %u\n", (unsigned int) itmp);
571 if (fscanf (procfile, "%u ", &itmp) > 0)
572 printf_filtered ("Start of text: 0x%x\n", itmp);
573 if (fscanf (procfile, "%u ", &itmp) > 0)
574 printf_filtered ("End of text: 0x%x\n", itmp);
575 if (fscanf (procfile, "%u ", &itmp) > 0)
576 printf_filtered ("Start of stack: 0x%x\n", itmp);
577 #if 0 /* Don't know how architecture-dependent the rest is...
578 Anyway the signal bitmap info is available from "status". */
579 if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */
580 printf_filtered ("Kernel stack pointer: 0x%x\n", itmp);
581 if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */
582 printf_filtered ("Kernel instr pointer: 0x%x\n", itmp);
583 if (fscanf (procfile, "%d ", &itmp) > 0)
584 printf_filtered ("Pending signals bitmap: 0x%x\n", itmp);
585 if (fscanf (procfile, "%d ", &itmp) > 0)
586 printf_filtered ("Blocked signals bitmap: 0x%x\n", itmp);
587 if (fscanf (procfile, "%d ", &itmp) > 0)
588 printf_filtered ("Ignored signals bitmap: 0x%x\n", itmp);
589 if (fscanf (procfile, "%d ", &itmp) > 0)
590 printf_filtered ("Catched signals bitmap: 0x%x\n", itmp);
591 if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */
592 printf_filtered ("wchan (system call): 0x%x\n", itmp);
593 #endif
594 fclose (procfile);
595 }
596 else
597 warning ("unable to open /proc file '%s'", fname1);
598 }
599 }
600
601 void
602 _initialize_linux_proc (void)
603 {
604 extern void inftarg_set_find_memory_regions ();
605 extern void inftarg_set_make_corefile_notes ();
606
607 inftarg_set_find_memory_regions (linux_find_memory_regions);
608 inftarg_set_make_corefile_notes (linux_make_note_section);
609
610 add_info ("proc", linux_info_proc_cmd,
611 "Show /proc process information about any running process.\n\
612 Specify any process id, or use the program being debugged by default.\n\
613 Specify any of the following keywords for detailed info:\n\
614 mappings -- list of mapped memory regions.\n\
615 stat -- list a bunch of random process info.\n\
616 status -- list a different bunch of random process info.\n\
617 all -- list all available /proc info.");
618 }
619
620 int
621 linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len, int write,
622 struct mem_attrib *attrib, struct target_ops *target)
623 {
624 int fd, ret;
625 char filename[64];
626
627 if (write)
628 return 0;
629
630 /* Don't bother for one word. */
631 if (len < 3 * sizeof (long))
632 return 0;
633
634 /* We could keep this file open and cache it - possibly one
635 per thread. That requires some juggling, but is even faster. */
636 sprintf (filename, "/proc/%d/mem", PIDGET (inferior_ptid));
637 fd = open (filename, O_RDONLY | O_LARGEFILE);
638 if (fd == -1)
639 return 0;
640
641 /* If pread64 is available, use it. It's faster if the kernel
642 supports it (only one syscall), and it's 64-bit safe even
643 on 32-bit platforms (for instance, SPARC debugging a SPARC64
644 application). */
645 #ifdef HAVE_PREAD64
646 if (pread64 (fd, myaddr, len, addr) != len)
647 #else
648 if (lseek (fd, addr, SEEK_SET) == -1 || read (fd, myaddr, len) != len)
649 #endif
650 ret = 0;
651 else
652 ret = len;
653
654 close (fd);
655 return ret;
656 }
657
658 /* Parse LINE as a signal set and add its set bits to SIGS. */
659
660 static void
661 linux_proc_add_line_to_sigset (const char *line, sigset_t *sigs)
662 {
663 int len = strlen (line) - 1;
664 const char *p;
665 int signum;
666
667 if (line[len] != '\n')
668 error ("Could not parse signal set: %s", line);
669
670 p = line;
671 signum = len * 4;
672 while (len-- > 0)
673 {
674 int digit;
675
676 if (*p >= '0' && *p <= '9')
677 digit = *p - '0';
678 else if (*p >= 'a' && *p <= 'f')
679 digit = *p - 'a' + 10;
680 else
681 error ("Could not parse signal set: %s", line);
682
683 signum -= 4;
684
685 if (digit & 1)
686 sigaddset (sigs, signum + 1);
687 if (digit & 2)
688 sigaddset (sigs, signum + 2);
689 if (digit & 4)
690 sigaddset (sigs, signum + 3);
691 if (digit & 8)
692 sigaddset (sigs, signum + 4);
693
694 p++;
695 }
696 }
697
698 /* Find process PID's pending signals from /proc/pid/status and set SIGS
699 to match. */
700
701 void
702 linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored)
703 {
704 FILE *procfile;
705 char buffer[MAXPATHLEN], fname[MAXPATHLEN];
706 int signum;
707
708 sigemptyset (pending);
709 sigemptyset (blocked);
710 sigemptyset (ignored);
711 sprintf (fname, "/proc/%d/status", pid);
712 procfile = fopen (fname, "r");
713 if (procfile == NULL)
714 error ("Could not open %s", fname);
715
716 while (fgets (buffer, MAXPATHLEN, procfile) != NULL)
717 {
718 /* Normal queued signals are on the SigPnd line in the status
719 file. However, 2.6 kernels also have a "shared" pending queue
720 for delivering signals to a thread group, so check for a ShdPnd
721 line also.
722
723 Unfortunately some Red Hat kernels include the shared pending queue
724 but not the ShdPnd status field. */
725
726 if (strncmp (buffer, "SigPnd:\t", 8) == 0)
727 linux_proc_add_line_to_sigset (buffer + 8, pending);
728 else if (strncmp (buffer, "ShdPnd:\t", 8) == 0)
729 linux_proc_add_line_to_sigset (buffer + 8, pending);
730 else if (strncmp (buffer, "SigBlk:\t", 8) == 0)
731 linux_proc_add_line_to_sigset (buffer + 8, blocked);
732 else if (strncmp (buffer, "SigIgn:\t", 8) == 0)
733 linux_proc_add_line_to_sigset (buffer + 8, ignored);
734 }
735
736 fclose (procfile);
737 }
This page took 0.046455 seconds and 4 git commands to generate.