summaryrefslogtreecommitdiff
path: root/libc/stdlib/abort.c
blob: a27dc3c1d5e89236bc03bb098fb301a12994a621 (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
/* 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>


/* Our last ditch effort to commit suicide */
#if defined(__alpha__)
#define ABORT_INSTRUCTION asm ("call_pal 0")
#elif defined(__hppa__)
#define ABORT_INSTRUCTION asm ("iitlbp %r0,(%r0)")
#elif defined(__i386__)
#define ABORT_INSTRUCTION asm ("hlt")
#elif defined(__ia64__)
#define ABORT_INSTRUCTION asm ("break 0")
#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 define for your arch
#endif

extern void _exit __P((int __status)) __attribute__ ((__noreturn__));
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;
# define LOCK	__pthread_mutex_lock(&mylock)
# define UNLOCK	__pthread_mutex_unlock(&mylock)
#else
# define LOCK
# define UNLOCK
#endif


/* 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++;
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;
	}
}