summaryrefslogtreecommitdiff
path: root/05/signal.h
blob: f885782b1d3e4fbf654dbab18c129db5ea7539e8 (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
#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 (*handler)(int);
	unsigned long flags;
	void (*restorer)(void);
	unsigned long 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

int __sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) {
	return __syscall(13, signum, act, oldact, 8, 0, 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.handler = func == SIG_DFL ? SIG_DFL : (void*)_signal_handler;
	act.mask = _sig_mask;
	act.flags = _SA_RESTORER;
	act.restorer = _signal_restorer;
	__sigaction(sig, &act, NULL);
	return ret;
}

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

#endif // _SIGNAL_H