summaryrefslogtreecommitdiff
path: root/libc/stdlib/abort.c
blob: 70b65a1b4dee8f8a929fb3ae2d2e909203052fe4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.  */

/* Hacked up for uClibc by Erik Andersen */

#define _GNU_SOURCE
#include <features.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

libc_hidden_proto(abort)

libc_hidden_proto(memset)
libc_hidden_proto(sigaction)
libc_hidden_proto(sigprocmask)
libc_hidden_proto(raise)
libc_hidden_proto(_exit)

/* Our last ditch effort to commit suicide */
#if defined(__alpha__)
#define ABORT_INSTRUCTION asm ("call_pal 0")
#elif defined(__arm__)
#define ABORT_INSTRUCTION asm ("bl abort")
#elif defined(__hppa__)
#define ABORT_INSTRUCTION asm ("iitlbp %r0,(%sr0,%r0)")
#elif defined(__i386__)
#define ABORT_INSTRUCTION asm ("hlt")
#elif defined(__ia64__)
#define ABORT_INSTRUCTION asm ("break 0")
#elif defined(__m68k__)
#define ABORT_INSTRUCTION asm ("illegal")
#elif defined(__mc68000__)
#define ABORT_INSTRUCTION asm (".long 0xffffffff")
#elif defined(__mips__)
#define ABORT_INSTRUCTION asm ("break 255")
#elif defined(__powerpc__)
#define ABORT_INSTRUCTION asm (".long 0")
#elif defined(__s390__)
#define ABORT_INSTRUCTION asm (".word 0")
#elif defined(__sparc__)
#define ABORT_INSTRUCTION asm ("unimp 0xf00")
#elif defined(__SH5__)
#define ABORT_INSTRUCTION asm ("movi 0x10, r9; shori 0xff, r9; trapa r9")
#elif defined(__sh2__)
#define ABORT_INSTRUCTION asm ("trapa #32")
#elif defined(__sh__)
#define ABORT_INSTRUCTION asm ("trapa #0xff")
#elif defined(__x86_64__)
#define ABORT_INSTRUCTION asm ("hlt")
#else
#define ABORT_INSTRUCTION
#warning no abort instruction defined for your arch
#endif

#ifdef __UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT__
extern void weak_function _stdio_term(void) attribute_hidden;
#endif
static int been_there_done_that = 0;

/* Be prepared in case multiple threads try to abort() */
#ifdef __UCLIBC_HAS_THREADS__
# include <pthread.h>
static pthread_mutex_t mylock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
#endif
#define LOCK	__pthread_mutex_lock(&mylock)
#define UNLOCK	__pthread_mutex_unlock(&mylock)

/* Cause an abnormal program termination with core-dump */
void abort(void)
{
	sigset_t sigset;

	/* Make sure we acquire the lock before proceeding */
	LOCK;

	/* Unmask SIGABRT to be sure we can get it */
	if (__sigemptyset(&sigset) == 0 && __sigaddset(&sigset, SIGABRT) == 0) {
		sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *) NULL);
	}

	while (1) {
		/* Try to suicide with a SIGABRT */
		if (been_there_done_that == 0) {
			been_there_done_that++;

#ifdef __UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT__
			/* If we are using stdio, try to shut it down.  At the very least,
			 * this will attempt to commit all buffered writes.  It may also
			 * unboffer all writable files, or close them outright.
			 * Check the stdio routines for details. */
			if (_stdio_term) {
				_stdio_term();
			}
#endif

abort_it:
			UNLOCK;
			raise(SIGABRT);
			LOCK;
		}

		/* Still here?  Try to remove any signal handlers */
		if (been_there_done_that == 1) {
			struct sigaction act;

			been_there_done_that++;
			memset(&act, '\0', sizeof(struct sigaction));
			act.sa_handler = SIG_DFL;
			__sigfillset(&act.sa_mask);
			act.sa_flags = 0;
			sigaction(SIGABRT, &act, NULL);

			goto abort_it;
		}

		/* Still here?  Try to suicide with an illegal instruction */
		if (been_there_done_that == 2) {
			been_there_done_that++;
			ABORT_INSTRUCTION;
		}

		/* Still here?  Try to at least exit */
		if (been_there_done_that == 3) {
			been_there_done_that++;
			_exit(127);
		}

		/* Still here?  We're screwed.  Sleepy time.  Good night. */
		while (1)
			/* Try for ever and ever */
			ABORT_INSTRUCTION;
	}
}
libc_hidden_def(abort)