2004-07-28 Andrew Cagney <cagney@gnu.org>
[platform/upstream/binutils.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 }