00788f22c7e0358ac4b64ac7b53f39f3347b14b6
[platform/upstream/linaro-glibc.git] / sysdeps / generic / abort.c
1 /* Copyright (C) 1991,93,95,96,97,98,2001,02 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <bits/libc-lock.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 /* Try to get a machine dependent instruction which will make the
27    program crash.  This is used in case everything else fails.  */
28 #include <abort-instr.h>
29 #ifndef ABORT_INSTRUCTION
30 /* No such instruction is available.  */
31 # define ABORT_INSTRUCTION
32 #endif
33
34 #ifdef USE_IN_LIBIO
35 # include <libio/libioP.h>
36 # define fflush(s) _IO_flush_all_lockp (0)
37 #endif
38
39 /* We must avoid to run in circles.  Therefore we remember how far we
40    already got.  */
41 static int stage;
42
43 /* We should be prepared for multiple threads trying to run abort.  */
44 __libc_lock_define_initialized_recursive (static, lock);
45
46
47 /* Cause an abnormal program termination with core-dump.  */
48 void
49 abort (void)
50 {
51   struct sigaction act;
52   sigset_t sigs;
53
54   /* First acquire the lock.  */
55   __libc_lock_lock_recursive (lock);
56
57   /* Now it's for sure we are alone.  But recursive calls are possible.  */
58
59   /* Unlock SIGABRT.  */
60   if (stage == 0)
61     {
62       ++stage;
63       if (__sigemptyset (&sigs) == 0 &&
64           __sigaddset (&sigs, SIGABRT) == 0)
65         __sigprocmask (SIG_UNBLOCK, &sigs, (sigset_t *) NULL);
66     }
67
68   /* Flush all streams.  We cannot close them now because the user
69      might have registered a handler for SIGABRT.  */
70   if (stage == 1)
71     {
72       ++stage;
73       fflush (NULL);
74     }
75
76   /* Send signal which possibly calls a user handler.  */
77   if (stage == 2)
78     {
79       /* This stage is special: we must allow repeated calls of
80          `abort' when a user defined handler for SIGABRT is installed.
81          This is risky since the `raise' implementation might also
82          fail but I don't see another possibility.  */
83       int save_stage = stage;
84
85       stage = 0;
86       __libc_lock_unlock_recursive (lock);
87
88       raise (SIGABRT);
89
90       __libc_lock_lock_recursive (lock);
91       stage = save_stage + 1;
92     }
93
94   /* There was a handler installed.  Now remove it.  */
95   if (stage == 3)
96     {
97       ++stage;
98       memset (&act, '\0', sizeof (struct sigaction));
99       act.sa_handler = SIG_DFL;
100       __sigfillset (&act.sa_mask);
101       act.sa_flags = 0;
102       __sigaction (SIGABRT, &act, NULL);
103     }
104
105   /* Now close the streams which also flushes the output the user
106      defined handler might has produced.  */
107   if (stage == 4)
108     {
109       ++stage;
110       __fcloseall ();
111     }
112
113   /* Try again.  */
114   if (stage == 5)
115     {
116       ++stage;
117       raise (SIGABRT);
118     }
119
120   /* Now try to abort using the system specific command.  */
121   if (stage == 6)
122     {
123       ++stage;
124       ABORT_INSTRUCTION;
125     }
126
127   /* If we can't signal ourselves and the abort instruction failed, exit.  */
128   if (stage == 7)
129     {
130       ++stage;
131       _exit (127);
132     }
133
134   /* If even this fails try to use the provided instruction to crash
135      or otherwise make sure we never return.  */
136   while (1)
137     /* Try for ever and ever.  */
138     ABORT_INSTRUCTION;
139 }
140 libc_hidden_def (abort)