summaryrefslogtreecommitdiff
path: root/05/signal.h
blob: ded960c08f84ac3494c969598d68309e8b3a1bfb (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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#ifndef _SIGNAL_H
#define _SIGNAL_H


#include <stdc_common.h>

typedef long sig_atomic_t; // there are no "asynchronous interrupts"

#define SIG_DFL ((void *)0)
#define SIG_IGN _sig_ign
#define SIG_ERR ((void *)-1)

typedef void (*_Sighandler)(int);

struct sigaction {
	void (*sa_handler)(int);
	#define sa_sigaction sa_handler
	unsigned long sa_flags;
	void (*sa_restorer)(void);
	unsigned long sa_mask;
};

unsigned char _signal_restorer[] = {
	0x48,0xb8,15,0,0,0,0,0,0,0, // mov rax, 15 (sigreturn)
	0x0f,0x05 // syscall
};

#define _SIGNAL_HANDLERS 0xfff000
#define _LE64(x) (x)&0xff,       ((x)>> 8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff, \
                 ((x)>>32)&0xff, ((x)>>40)&0xff, ((x)>>48)&0xff, (x)>>56

// we need to do this weird indirection because linux has a different
// calling convention from us.

unsigned char _signal_handler[] = {
	// signal # passed in rdi
	0x48,0x89,0xf8,                     // mov rax, rdi (signal #)
	0x50,                               // push rax
	0x50,                               // push rax (allocate space for return value)
	0x48,0xb8,_LE64(_SIGNAL_HANDLERS),  // mov rax, _SIGNAL_HANDLERS
	0x48,0x89,0xc3,                     // mov rbx, rax
	0x48,0x89,0xf8,                     // mov rax, rdi (signal #)
	0x48,0xc1,0xe0,0x03,                // shl rax, 3
	0x48,0x01,0xd8,                     // add rax, rbx
	0x48,0x89,0xc3,                     // mov rbx, rax
	0x48,0x8b,0x03,                     // mov rax, [rbx]
	0xff,0xd0,                          // call rax
	0x48,0x81,0xc4,16,0,0,0,            // add rsp, 16
	0xc3                                // ret
};

#define _SA_RESTORER 0x04000000
#define SA_SIGINFO 4
#define SA_RESETHAND 0x80000000

int __sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) {
	return __syscall(13, signum, act, oldact, 8, 0, 0);
}

void sigemptyset(unsigned long *set) {
	*set = 0;
}

void _sig_ign(int signal) {
	return;
}

static unsigned long _sig_mask = 0;

_Sighandler signal(int sig, _Sighandler func) {
	void **handlers = _SIGNAL_HANDLERS;
	_Sighandler ret = handlers[sig];
	if (func == SIG_IGN) {
		func = _sig_ign;
	}
	handlers[sig] = func;
	
	if (func == SIG_DFL) {
		_sig_mask &= ~(1ul << (sig-1));
	} else {
		_sig_mask |= 1ul << (sig-1);
	}
	struct sigaction act = {0};
	act.sa_handler = func == SIG_DFL ? SIG_DFL : (void*)_signal_handler;
	act.sa_mask = _sig_mask;
	act.sa_flags = _SA_RESTORER;
	act.sa_restorer = _signal_restorer;
	__sigaction(sig, &act, NULL);
	return ret;
}

int raise(int signal) {
	return kill(getpid(), signal);
}

#define FPE_INTDIV 1
#define FPE_FLTDIV 3

#define __SI_MAX_SIZE	128
#if __WORDSIZE == 64
# define __SI_PAD_SIZE	((__SI_MAX_SIZE / sizeof (int)) - 4)
#else
# define __SI_PAD_SIZE	((__SI_MAX_SIZE / sizeof (int)) - 3)
#endif

#ifndef __SI_ALIGNMENT
# define __SI_ALIGNMENT		/* nothing */
#endif
#ifndef __SI_BAND_TYPE
# define __SI_BAND_TYPE		long int
#endif
#ifndef __SI_CLOCK_T
# define __SI_CLOCK_T		__clock_t
#endif
#ifndef __SI_ERRNO_THEN_CODE
# define __SI_ERRNO_THEN_CODE	1
#endif
#ifndef __SI_HAVE_SIGSYS
# define __SI_HAVE_SIGSYS	1
#endif
#ifndef __SI_SIGFAULT_ADDL
# define __SI_SIGFAULT_ADDL	/* nothing */
#endif

typedef int __pid_t;
typedef unsigned __uid_t;

union __sigval
{
  int __sival_int;
  void *__sival_ptr;
};

typedef union __sigval __sigval_t;
typedef long __clock_t;

typedef struct
  {
    int si_signo;		/* Signal number.  */
#if __SI_ERRNO_THEN_CODE
    int si_errno;		/* If non-zero, an errno value associated with
				   this signal, as defined in <errno.h>.  */
    int si_code;		/* Signal code.  */
#else
    int si_code;
    int si_errno;
#endif
#if __WORDSIZE == 64
    int __pad0;			/* Explicit padding.  */
#endif

    union
      {
	int _pad[__SI_PAD_SIZE];

	 /* kill().  */
	struct
	  {
	    __pid_t si_pid;	/* Sending process ID.  */
	    __uid_t si_uid;	/* Real user ID of sending process.  */
	  } _kill;

	/* POSIX.1b timers.  */
	struct
	  {
	    int si_tid;		/* Timer ID.  */
	    int si_overrun;	/* Overrun count.  */
	    __sigval_t si_sigval;	/* Signal value.  */
	  } _timer;

	/* POSIX.1b signals.  */
	struct
	  {
	    __pid_t si_pid;	/* Sending process ID.  */
	    __uid_t si_uid;	/* Real user ID of sending process.  */
	    __sigval_t si_sigval;	/* Signal value.  */
	  } _rt;

	/* SIGCHLD.  */
	struct
	  {
	    __pid_t si_pid;	/* Which child.	 */
	    __uid_t si_uid;	/* Real user ID of sending process.  */
	    int si_status;	/* Exit value or signal.  */
	    __SI_CLOCK_T si_utime;
	    __SI_CLOCK_T si_stime;
	  } _sigchld;

	/* SIGILL, SIGFPE, SIGSEGV, SIGBUS.  */
	struct
	  {
	    void *si_addr;	    /* Faulting insn/memory ref.  */
	    __SI_SIGFAULT_ADDL
	    short int si_addr_lsb;  /* Valid LSB of the reported address.  */
	    union
	      {
		/* used when si_code=SEGV_BNDERR */
		struct
		  {
		    void *_lower;
		    void *_upper;
		  } _addr_bnd;
		/* used when si_code=SEGV_PKUERR */
		uint32_t _pkey;
	      } _bounds;
	  } _sigfault;

	/* SIGPOLL.  */
	struct
	  {
	    __SI_BAND_TYPE si_band;	/* Band event for SIGPOLL.  */
	    int si_fd;
	  } _sigpoll;

	/* SIGSYS.  */
#if __SI_HAVE_SIGSYS
	struct
	  {
	    void *_call_addr;	/* Calling user insn.  */
	    int _syscall;	/* Triggering system call number.  */
	    unsigned int _arch; /* AUDIT_ARCH_* of syscall.  */
	  } _sigsys;
#endif
      } _sifields;
  } siginfo_t __SI_ALIGNMENT;


/* X/Open requires some more fields with fixed names.  */
#define si_pid		_sifields._kill.si_pid
#define si_uid		_sifields._kill.si_uid
#define si_timerid	_sifields._timer.si_tid
#define si_overrun	_sifields._timer.si_overrun
#define si_status	_sifields._sigchld.si_status
#define si_utime	_sifields._sigchld.si_utime
#define si_stime	_sifields._sigchld.si_stime
#define si_value	_sifields._rt.si_sigval
#define si_int		_sifields._rt.si_sigval.sival_int
#define si_ptr		_sifields._rt.si_sigval.sival_ptr
#define si_addr		_sifields._sigfault.si_addr
#define si_addr_lsb	_sifields._sigfault.si_addr_lsb
#define si_lower	_sifields._sigfault._bounds._addr_bnd._lower
#define si_upper	_sifields._sigfault._bounds._addr_bnd._upper
#define si_pkey		_sifields._sigfault._bounds._pkey
#define si_band		_sifields._sigpoll.si_band
#define si_fd		_sifields._sigpoll.si_fd
#if __SI_HAVE_SIGSYS
# define si_call_addr	_sifields._sigsys._call_addr
# define si_syscall	_sifields._sigsys._syscall
# define si_arch	_sifields._sigsys._arch
#endif


#endif // _SIGNAL_H