1 /* Extended support for using signal values.
2    Copyright (C) 1992 Free Software Foundation, Inc.
3    Written by Fred Fish.  fnf@cygnus.com
4 
5 This file is part of the libiberty library.
6 Libiberty is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10 
11 Libiberty is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Library General Public License for more details.
15 
16 You should have received a copy of the GNU Library General Public
17 License along with libiberty; see the file COPYING.LIB.  If
18 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19 Cambridge, MA 02139, USA.  */
20 
21 #include "config.h"
22 
23 #include <stdio.h>
24 #include <signal.h>
25 
26 /*  Routines imported from standard C runtime libraries. */
27 
28 #ifdef __STDC__
29 #include <stddef.h>
30 extern void *malloc (size_t size);				/* 4.10.3.3 */
31 extern void *memset (void *s, int c, size_t n);			/* 4.11.6.1 */
32 #else	/* !__STDC__ */
33 extern char *malloc ();		/* Standard memory allocater */
34 extern char *memset ();
35 #endif	/* __STDC__ */
36 
37 #ifndef NULL
38 #  ifdef __STDC__
39 #    define NULL (void *) 0
40 #  else
41 #    define NULL 0
42 #  endif
43 #endif
44 
45 #ifndef MAX
46 #  define MAX(a,b) ((a) > (b) ? (a) : (b))
47 #endif
48 
49 /* Translation table for signal values.
50 
51    Note that this table is generally only accessed when it is used at runtime
52    to initialize signal name and message tables that are indexed by signal
53    value.
54 
55    Not all of these signals will exist on all systems.  This table is the only
56    thing that should have to be updated as new signal numbers are introduced.
57    It's sort of ugly, but at least its portable. */
58 
59 static struct signal_info
60 {
61   int value;		/* The numeric value from <signal.h> */
62   char *name;		/* The equivalent symbolic value */
63   char *msg;		/* Short message about this value */
64 } signal_table[] =
65 {
66 #if defined (SIGHUP)
67   SIGHUP, "SIGHUP", "Hangup",
68 #endif
69 #if defined (SIGINT)
70   SIGINT, "SIGINT", "Interrupt",
71 #endif
72 #if defined (SIGQUIT)
73   SIGQUIT, "SIGQUIT", "Quit",
74 #endif
75 #if defined (SIGILL)
76   SIGILL, "SIGILL", "Illegal instruction",
77 #endif
78 #if defined (SIGTRAP)
79   SIGTRAP, "SIGTRAP", "Trace/breakpoint trap",
80 #endif
81 /* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT
82    overrides SIGIOT.  SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */
83 #if defined (SIGIOT)
84   SIGIOT, "SIGIOT", "IOT trap",
85 #endif
86 #if defined (SIGABRT)
87   SIGABRT, "SIGABRT", "Aborted",
88 #endif
89 #if defined (SIGEMT)
90   SIGEMT, "SIGEMT", "Emulation trap",
91 #endif
92 #if defined (SIGFPE)
93   SIGFPE, "SIGFPE", "Arithmetic exception",
94 #endif
95 #if defined (SIGKILL)
96   SIGKILL, "SIGKILL", "Killed",
97 #endif
98 #if defined (SIGBUS)
99   SIGBUS, "SIGBUS", "Bus error",
100 #endif
101 #if defined (SIGSEGV)
102   SIGSEGV, "SIGSEGV", "Segmentation fault",
103 #endif
104 #if defined (SIGSYS)
105   SIGSYS, "SIGSYS", "Bad system call",
106 #endif
107 #if defined (SIGPIPE)
108   SIGPIPE, "SIGPIPE", "Broken pipe",
109 #endif
110 #if defined (SIGALRM)
111   SIGALRM, "SIGALRM", "Alarm clock",
112 #endif
113 #if defined (SIGTERM)
114   SIGTERM, "SIGTERM", "Terminated",
115 #endif
116 #if defined (SIGUSR1)
117   SIGUSR1, "SIGUSR1", "User defined signal 1",
118 #endif
119 #if defined (SIGUSR2)
120   SIGUSR2, "SIGUSR2", "User defined signal 2",
121 #endif
122 /* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD
123    overrides SIGCLD.  SIGCHLD is in POXIX.1 */
124 #if defined (SIGCLD)
125   SIGCLD, "SIGCLD", "Child status changed",
126 #endif
127 #if defined (SIGCHLD)
128   SIGCHLD, "SIGCHLD", "Child status changed",
129 #endif
130 #if defined (SIGPWR)
131   SIGPWR, "SIGPWR", "Power fail/restart",
132 #endif
133 #if defined (SIGWINCH)
134   SIGWINCH, "SIGWINCH", "Window size changed",
135 #endif
136 #if defined (SIGURG)
137   SIGURG, "SIGURG", "Urgent I/O condition",
138 #endif
139 #if defined (SIGIO)
140   /* "I/O pending has also been suggested, but is misleading since the
141      signal only happens when the process has asked for it, not everytime
142      I/O is pending. */
143   SIGIO, "SIGIO", "I/O possible",
144 #endif
145 #if defined (SIGPOLL)
146   SIGPOLL, "SIGPOLL", "Pollable event occurred",
147 #endif
148 #if defined (SIGSTOP)
149   SIGSTOP, "SIGSTOP", "Stopped (signal)",
150 #endif
151 #if defined (SIGTSTP)
152   SIGTSTP, "SIGTSTP", "Stopped (user)",
153 #endif
154 #if defined (SIGCONT)
155   SIGCONT, "SIGCONT", "Continued",
156 #endif
157 #if defined (SIGTTIN)
158   SIGTTIN, "SIGTTIN", "Stopped (tty input)",
159 #endif
160 #if defined (SIGTTOU)
161   SIGTTOU, "SIGTTOU", "Stopped (tty output)",
162 #endif
163 #if defined (SIGVTALRM)
164   SIGVTALRM, "SIGVTALRM", "Virtual timer expired",
165 #endif
166 #if defined (SIGPROF)
167   SIGPROF, "SIGPROF", "Profiling timer expired",
168 #endif
169 #if defined (SIGXCPU)
170   SIGXCPU, "SIGXCPU", "CPU time limit exceeded",
171 #endif
172 #if defined (SIGXFSZ)
173   SIGXFSZ, "SIGXFSZ", "File size limit exceeded",
174 #endif
175 #if defined (SIGWIND)
176   SIGWIND, "SIGWIND", "SIGWIND",
177 #endif
178 #if defined (SIGPHONE)
179   SIGPHONE, "SIGPHONE", "SIGPHONE",
180 #endif
181 #if defined (SIGLOST)
182   SIGLOST, "SIGLOST", "Resource lost",
183 #endif
184 #if defined (SIGWAITING)
185   SIGWAITING, "SIGWAITING", "Process's LWPs are blocked",
186 #endif
187 #if defined (SIGLWP)
188   SIGLWP, "SIGLWP", "Signal LWP",
189 #endif
190   0, NULL, NULL
191 };
192 
193 /* Translation table allocated and initialized at runtime.  Indexed by the
194    signal value to find the equivalent symbolic value. */
195 
196 static char **signal_names;
197 static int num_signal_names = 0;
198 
199 /* Translation table allocated and initialized at runtime, if it does not
200    already exist in the host environment.  Indexed by the signal value to find
201    the descriptive string.
202 
203    We don't export it for use in other modules because even though it has the
204    same name, it differs from other implementations in that it is dynamically
205    initialized rather than statically initialized. */
206 
207 #ifdef NEED_sys_siglist
208 
209 static int sys_nsig;
210 #ifdef notdef
211 static char **sys_siglist;
212 #endif
213 
214 #else
215 
216 static int sys_nsig = NSIG;
217 #ifdef notdef
218 #ifdef __STDC__
219 extern char * const sys_siglist[];
220 #else
221 extern char *sys_siglist[];
222 #endif
223 #endif
224 #endif
225 
226 
227 /*
228 
229 NAME
230 
231 	init_signal_tables -- initialize the name and message tables
232 
233 SYNOPSIS
234 
235 	static void init_signal_tables ();
236 
237 DESCRIPTION
238 
239 	Using the signal_table, which is initialized at compile time, generate
240 	the signal_names and the sys_siglist (if needed) tables, which are
241 	indexed at runtime by a specific signal value.
242 
243 BUGS
244 
245 	The initialization of the tables may fail under low memory conditions,
246 	in which case we don't do anything particularly useful, but we don't
247 	bomb either.  Who knows, it might succeed at a later point if we free
248 	some memory in the meantime.  In any case, the other routines know
249 	how to deal with lack of a table after trying to initialize it.  This
250 	may or may not be considered to be a bug, that we don't specifically
251 	warn about this particular failure mode.
252 
253 */
254 
255 static void
256 init_signal_tables ()
257 {
258   struct signal_info *eip;
259   int nbytes;
260 
261   /* If we haven't already scanned the signal_table once to find the maximum
262      signal value, then go find it now. */
263 
264   if (num_signal_names == 0)
265     {
266       for (eip = signal_table; eip -> name != NULL; eip++)
267 	{
268 	  if (eip -> value >= num_signal_names)
269 	    {
270 	      num_signal_names = eip -> value + 1;
271 	    }
272 	}
273     }
274 
275   /* Now attempt to allocate the signal_names table, zero it out, and then
276      initialize it from the statically initialized signal_table. */
277 
278   if (signal_names == NULL)
279     {
280       nbytes = num_signal_names * sizeof (char *);
281       if ((signal_names = (char **) malloc (nbytes)) != NULL)
282 	{
283 	  memset (signal_names, 0, nbytes);
284 	  for (eip = signal_table; eip -> name != NULL; eip++)
285 	    {
286 	      signal_names[eip -> value] = eip -> name;
287 	    }
288 	}
289     }
290 
291 #ifdef NEED_sys_siglist
292 
293   /* Now attempt to allocate the sys_siglist table, zero it out, and then
294      initialize it from the statically initialized signal_table. */
295 
296   if (sys_siglist == NULL)
297     {
298       nbytes = num_signal_names * sizeof (char *);
299       if ((sys_siglist = (char **) malloc (nbytes)) != NULL)
300 	{
301 	  memset (sys_siglist, 0, nbytes);
302 	  sys_nsig = num_signal_names;
303 	  for (eip = signal_table; eip -> name != NULL; eip++)
304 	    {
305 	      sys_siglist[eip -> value] = eip -> msg;
306 	    }
307 	}
308     }
309 
310 #endif
311 
312 }
313 
314 
315 /*
316 
317 NAME
318 
319 	signo_max -- return the max signo value
320 
321 SYNOPSIS
322 
323 	int signo_max ();
324 
325 DESCRIPTION
326 
327 	Returns the maximum signo value for which a corresponding symbolic
328 	name or message is available.  Note that in the case where
329 	we use the sys_siglist supplied by the system, it is possible for
330 	there to be more symbolic names than messages, or vice versa.
331 	In fact, the manual page for psignal(3b) explicitly warns that one
332 	should check the size of the table (NSIG) before indexing it,
333 	since new signal codes may be added to the system before they are
334 	added to the table.  Thus NSIG might be smaller than value
335 	implied by the largest signo value defined in <signal.h>.
336 
337 	We return the maximum value that can be used to obtain a meaningful
338 	symbolic name or message.
339 
340 */
341 
342 int
343 signo_max ()
344 {
345   int maxsize;
346 
347   if (signal_names == NULL)
348     {
349       init_signal_tables ();
350     }
351   maxsize = MAX (sys_nsig, num_signal_names);
352   return (maxsize - 1);
353 }
354 
355 
356 /*
357 
358 NAME
359 
360 	strsignal -- map a signal number to a signal message string
361 
362 SYNOPSIS
363 
364 	char *strsignal (int signo)
365 
366 DESCRIPTION
367 
368 	Maps an signal number to an signal message string, the contents of
369 	which are implementation defined.  On systems which have the external
370 	variable sys_siglist, these strings will be the same as the ones used
371 	by psignal().
372 
373 	If the supplied signal number is within the valid range of indices
374 	for the sys_siglist, but no message is available for the particular
375 	signal number, then returns the string "Signal NUM", where NUM is the
376 	signal number.
377 
378 	If the supplied signal number is not a valid index into sys_siglist,
379 	returns NULL.
380 
381 	The returned string is only guaranteed to be valid only until the
382 	next call to strsignal.
383 
384 */
385 
386 char *
387 strsignal (signo)
388   int signo;
389 {
390   char *msg;
391   static char buf[32];
392 
393 #ifdef NEED_sys_siglist
394 
395   if (signal_names == NULL)
396     {
397       init_signal_tables ();
398     }
399 
400 #endif
401 
402   if ((signo < 0) || (signo >= sys_nsig))
403     {
404       /* Out of range, just return NULL */
405       msg = NULL;
406     }
407   else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL))
408     {
409       /* In range, but no sys_siglist or no entry at this index. */
410       sprintf (buf, "Signal %d", signo);
411       msg = buf;
412     }
413   else
414     {
415       /* In range, and a valid message.  Just return the message. */
416       msg = (char*)sys_siglist[signo];
417     }
418 
419   return (msg);
420 }
421 
422 
423 /*
424 
425 NAME
426 
427 	strsigno -- map an signal number to a symbolic name string
428 
429 SYNOPSIS
430 
431 	char *strsigno (int signo)
432 
433 DESCRIPTION
434 
435 	Given an signal number, returns a pointer to a string containing
436 	the symbolic name of that signal number, as found in <signal.h>.
437 
438 	If the supplied signal number is within the valid range of indices
439 	for symbolic names, but no name is available for the particular
440 	signal number, then returns the string "Signal NUM", where NUM is
441 	the signal number.
442 
443 	If the supplied signal number is not within the range of valid
444 	indices, then returns NULL.
445 
446 BUGS
447 
448 	The contents of the location pointed to are only guaranteed to be
449 	valid until the next call to strsigno.
450 
451 */
452 
453 char *
454 strsigno (signo)
455   int signo;
456 {
457   char *name;
458   static char buf[32];
459 
460   if (signal_names == NULL)
461     {
462       init_signal_tables ();
463     }
464 
465   if ((signo < 0) || (signo >= num_signal_names))
466     {
467       /* Out of range, just return NULL */
468       name = NULL;
469     }
470   else if ((signal_names == NULL) || (signal_names[signo] == NULL))
471     {
472       /* In range, but no signal_names or no entry at this index. */
473       sprintf (buf, "Signal %d", signo);
474       name = buf;
475     }
476   else
477     {
478       /* In range, and a valid name.  Just return the name. */
479       name = signal_names[signo];
480     }
481 
482   return (name);
483 }
484 
485 
486 /*
487 
488 NAME
489 
490 	strtosigno -- map a symbolic signal name to a numeric value
491 
492 SYNOPSIS
493 
494 	int strtosigno (char *name)
495 
496 DESCRIPTION
497 
498 	Given the symbolic name of a signal, map it to a signal number.
499 	If no translation is found, returns 0.
500 
501 */
502 
503 int
504 strtosigno (name)
505   char *name;
506 {
507   int signo = 0;
508 
509   if (name != NULL)
510     {
511       if (signal_names == NULL)
512 	{
513 	  init_signal_tables ();
514 	}
515       for (signo = 0; signo < num_signal_names; signo++)
516 	{
517 	  if ((signal_names[signo] != NULL) &&
518 	      (strcmp (name, signal_names[signo]) == 0))
519 	    {
520 	      break;
521 	    }
522 	}
523       if (signo == num_signal_names)
524 	{
525 	  signo = 0;
526 	}
527     }
528   return (signo);
529 }
530 
531 
532 /*
533 
534 NAME
535 
536 	psignal -- print message about signal to stderr
537 
538 SYNOPSIS
539 
540 	void psignal (unsigned signo, char *message);
541 
542 DESCRIPTION
543 
544 	Print to the standard error the message, followed by a colon,
545 	followed by the description of the signal specified by signo,
546 	followed by a newline.
547 */
548 
549 #ifdef NEED_psignal
550 
551 void
552 psignal (signo, message)
553   unsigned signo;
554   char *message;
555 {
556   if (signal_names == NULL)
557     {
558       init_signal_tables ();
559     }
560   if ((signo <= 0) || (signo >= sys_nsig))
561     {
562       fprintf (stderr, "%s: unknown signal\n", message);
563     }
564   else
565     {
566       fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]);
567     }
568 }
569 
570 #endif	/* NEED_psignal */
571 
572 
573 /* A simple little main that does nothing but print all the signal translations
574    if MAIN is defined and this file is compiled and linked. */
575 
576 #ifdef MAIN
577 
578 main ()
579 {
580   int signo;
581   int maxsigno;
582   char *name;
583   char *msg;
584   char *strsigno ();
585   char *strsignal ();
586 
587   maxsigno = signo_max ();
588   printf ("%d entries in names table.\n", num_signal_names);
589   printf ("%d entries in messages table.\n", sys_nsig);
590   printf ("%d is max useful index.\n", maxsigno);
591 
592   /* Keep printing values until we get to the end of *both* tables, not
593      *either* table.  Note that knowing the maximum useful index does *not*
594      relieve us of the responsibility of testing the return pointer for
595      NULL. */
596 
597   for (signo = 0; signo <= maxsigno; signo++)
598     {
599       name = strsigno (signo);
600       name = (name == NULL) ? "<NULL>" : name;
601       msg = strsignal (signo);
602       msg = (msg == NULL) ? "<NULL>" : msg;
603       printf ("%-4d%-18s%s\n", signo, name, msg);
604     }
605 }
606 
607 #endif
608