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 static char **sys_siglist;
211 
212 #else
213 
214 static int sys_nsig = NSIG;
215 #ifdef __STDC__
216 extern const char * const sys_siglist[];
217 #else
218 extern char *sys_siglist[];
219 #endif
220 #endif
221 
222 
223 /*
224 
225 NAME
226 
227 	init_signal_tables -- initialize the name and message tables
228 
229 SYNOPSIS
230 
231 	static void init_signal_tables ();
232 
233 DESCRIPTION
234 
235 	Using the signal_table, which is initialized at compile time, generate
236 	the signal_names and the sys_siglist (if needed) tables, which are
237 	indexed at runtime by a specific signal value.
238 
239 BUGS
240 
241 	The initialization of the tables may fail under low memory conditions,
242 	in which case we don't do anything particularly useful, but we don't
243 	bomb either.  Who knows, it might succeed at a later point if we free
244 	some memory in the meantime.  In any case, the other routines know
245 	how to deal with lack of a table after trying to initialize it.  This
246 	may or may not be considered to be a bug, that we don't specifically
247 	warn about this particular failure mode.
248 
249 */
250 
251 static void
252 init_signal_tables ()
253 {
254   struct signal_info *eip;
255   int nbytes;
256 
257   /* If we haven't already scanned the signal_table once to find the maximum
258      signal value, then go find it now. */
259 
260   if (num_signal_names == 0)
261     {
262       for (eip = signal_table; eip -> name != NULL; eip++)
263 	{
264 	  if (eip -> value >= num_signal_names)
265 	    {
266 	      num_signal_names = eip -> value + 1;
267 	    }
268 	}
269     }
270 
271   /* Now attempt to allocate the signal_names table, zero it out, and then
272      initialize it from the statically initialized signal_table. */
273 
274   if (signal_names == NULL)
275     {
276       nbytes = num_signal_names * sizeof (char *);
277       if ((signal_names = (char **) malloc (nbytes)) != NULL)
278 	{
279 	  memset (signal_names, 0, nbytes);
280 	  for (eip = signal_table; eip -> name != NULL; eip++)
281 	    {
282 	      signal_names[eip -> value] = eip -> name;
283 	    }
284 	}
285     }
286 
287 #ifdef NEED_sys_siglist
288 
289   /* Now attempt to allocate the sys_siglist table, zero it out, and then
290      initialize it from the statically initialized signal_table. */
291 
292   if (sys_siglist == NULL)
293     {
294       nbytes = num_signal_names * sizeof (char *);
295       if ((sys_siglist = (char **) malloc (nbytes)) != NULL)
296 	{
297 	  memset (sys_siglist, 0, nbytes);
298 	  sys_nsig = num_signal_names;
299 	  for (eip = signal_table; eip -> name != NULL; eip++)
300 	    {
301 	      sys_siglist[eip -> value] = eip -> msg;
302 	    }
303 	}
304     }
305 
306 #endif
307 
308 }
309 
310 
311 /*
312 
313 NAME
314 
315 	signo_max -- return the max signo value
316 
317 SYNOPSIS
318 
319 	int signo_max ();
320 
321 DESCRIPTION
322 
323 	Returns the maximum signo value for which a corresponding symbolic
324 	name or message is available.  Note that in the case where
325 	we use the sys_siglist supplied by the system, it is possible for
326 	there to be more symbolic names than messages, or vice versa.
327 	In fact, the manual page for psignal(3b) explicitly warns that one
328 	should check the size of the table (NSIG) before indexing it,
329 	since new signal codes may be added to the system before they are
330 	added to the table.  Thus NSIG might be smaller than value
331 	implied by the largest signo value defined in <signal.h>.
332 
333 	We return the maximum value that can be used to obtain a meaningful
334 	symbolic name or message.
335 
336 */
337 
338 int
339 signo_max ()
340 {
341   int maxsize;
342 
343   if (signal_names == NULL)
344     {
345       init_signal_tables ();
346     }
347   maxsize = MAX (sys_nsig, num_signal_names);
348   return (maxsize - 1);
349 }
350 
351 
352 /*
353 
354 NAME
355 
356 	strsignal -- map a signal number to a signal message string
357 
358 SYNOPSIS
359 
360 	char *strsignal (int signo)
361 
362 DESCRIPTION
363 
364 	Maps an signal number to an signal message string, the contents of
365 	which are implementation defined.  On systems which have the external
366 	variable sys_siglist, these strings will be the same as the ones used
367 	by psignal().
368 
369 	If the supplied signal number is within the valid range of indices
370 	for the sys_siglist, but no message is available for the particular
371 	signal number, then returns the string "Signal NUM", where NUM is the
372 	signal number.
373 
374 	If the supplied signal number is not a valid index into sys_siglist,
375 	returns NULL.
376 
377 	The returned string is only guaranteed to be valid only until the
378 	next call to strsignal.
379 
380 */
381 
382 char *
383 strsignal (signo)
384   int signo;
385 {
386   char *msg;
387   static char buf[32];
388 
389 #ifdef NEED_sys_siglist
390 
391   if (signal_names == NULL)
392     {
393       init_signal_tables ();
394     }
395 
396 #endif
397 
398   if ((signo < 0) || (signo >= sys_nsig))
399     {
400       /* Out of range, just return NULL */
401       msg = NULL;
402     }
403   else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL))
404     {
405       /* In range, but no sys_siglist or no entry at this index. */
406       sprintf (buf, "Signal %d", signo);
407       msg = buf;
408     }
409   else
410     {
411       /* In range, and a valid message.  Just return the message. */
412       msg = (char*)sys_siglist[signo];
413     }
414 
415   return (msg);
416 }
417 
418 
419 /*
420 
421 NAME
422 
423 	strsigno -- map an signal number to a symbolic name string
424 
425 SYNOPSIS
426 
427 	char *strsigno (int signo)
428 
429 DESCRIPTION
430 
431 	Given an signal number, returns a pointer to a string containing
432 	the symbolic name of that signal number, as found in <signal.h>.
433 
434 	If the supplied signal number is within the valid range of indices
435 	for symbolic names, but no name is available for the particular
436 	signal number, then returns the string "Signal NUM", where NUM is
437 	the signal number.
438 
439 	If the supplied signal number is not within the range of valid
440 	indices, then returns NULL.
441 
442 BUGS
443 
444 	The contents of the location pointed to are only guaranteed to be
445 	valid until the next call to strsigno.
446 
447 */
448 
449 char *
450 strsigno (signo)
451   int signo;
452 {
453   char *name;
454   static char buf[32];
455 
456   if (signal_names == NULL)
457     {
458       init_signal_tables ();
459     }
460 
461   if ((signo < 0) || (signo >= num_signal_names))
462     {
463       /* Out of range, just return NULL */
464       name = NULL;
465     }
466   else if ((signal_names == NULL) || (signal_names[signo] == NULL))
467     {
468       /* In range, but no signal_names or no entry at this index. */
469       sprintf (buf, "Signal %d", signo);
470       name = buf;
471     }
472   else
473     {
474       /* In range, and a valid name.  Just return the name. */
475       name = signal_names[signo];
476     }
477 
478   return (name);
479 }
480 
481 
482 /*
483 
484 NAME
485 
486 	strtosigno -- map a symbolic signal name to a numeric value
487 
488 SYNOPSIS
489 
490 	int strtosigno (char *name)
491 
492 DESCRIPTION
493 
494 	Given the symbolic name of a signal, map it to a signal number.
495 	If no translation is found, returns 0.
496 
497 */
498 
499 int
500 strtosigno (name)
501   char *name;
502 {
503   int signo = 0;
504 
505   if (name != NULL)
506     {
507       if (signal_names == NULL)
508 	{
509 	  init_signal_tables ();
510 	}
511       for (signo = 0; signo < num_signal_names; signo++)
512 	{
513 	  if ((signal_names[signo] != NULL) &&
514 	      (strcmp (name, signal_names[signo]) == 0))
515 	    {
516 	      break;
517 	    }
518 	}
519       if (signo == num_signal_names)
520 	{
521 	  signo = 0;
522 	}
523     }
524   return (signo);
525 }
526 
527 
528 /*
529 
530 NAME
531 
532 	psignal -- print message about signal to stderr
533 
534 SYNOPSIS
535 
536 	void psignal (unsigned signo, char *message);
537 
538 DESCRIPTION
539 
540 	Print to the standard error the message, followed by a colon,
541 	followed by the description of the signal specified by signo,
542 	followed by a newline.
543 */
544 
545 #ifdef NEED_psignal
546 
547 void
548 psignal (signo, message)
549   unsigned signo;
550   char *message;
551 {
552   if (signal_names == NULL)
553     {
554       init_signal_tables ();
555     }
556   if ((signo <= 0) || (signo >= sys_nsig))
557     {
558       fprintf (stderr, "%s: unknown signal\n", message);
559     }
560   else
561     {
562       fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]);
563     }
564 }
565 
566 #endif	/* NEED_psignal */
567 
568 
569 /* A simple little main that does nothing but print all the signal translations
570    if MAIN is defined and this file is compiled and linked. */
571 
572 #ifdef MAIN
573 
574 main ()
575 {
576   int signo;
577   int maxsigno;
578   char *name;
579   char *msg;
580   char *strsigno ();
581   char *strsignal ();
582 
583   maxsigno = signo_max ();
584   printf ("%d entries in names table.\n", num_signal_names);
585   printf ("%d entries in messages table.\n", sys_nsig);
586   printf ("%d is max useful index.\n", maxsigno);
587 
588   /* Keep printing values until we get to the end of *both* tables, not
589      *either* table.  Note that knowing the maximum useful index does *not*
590      relieve us of the responsibility of testing the return pointer for
591      NULL. */
592 
593   for (signo = 0; signo <= maxsigno; signo++)
594     {
595       name = strsigno (signo);
596       name = (name == NULL) ? "<NULL>" : name;
597       msg = strsignal (signo);
598       msg = (msg == NULL) ? "<NULL>" : msg;
599       printf ("%-4d%-18s%s\n", signo, name, msg);
600     }
601 }
602 
603 #endif
604