summaryrefslogtreecommitdiff
path: root/src/runtime/linux/signal.c
blob: 5805f35abf5adf8b2721d734d81a1084d8938456 (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
// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "runtime.h"
#include "defs.h"
#include "signals.h"

/* From /usr/include/asm-x86_64/sigcontext.h */
struct _fpstate {
  uint16   cwd;
  uint16   swd;
  uint16   twd;    /* Note this is not the same as the 32bit/x87/FSAVE twd */
  uint16   fop;
  uint64   rip;
  uint32   rdp;
  uint32   mxcsr;
  uint32   mxcsr_mask;
  uint32   st_space[32];   /* 8*16 bytes for each FP-reg */
  uint32   xmm_space[64];  /* 16*16 bytes for each XMM-reg  */
  uint32   reserved2[24];
};

struct sigcontext {
  uint64 r8;
  uint64 r9;
  uint64 r10;
  uint64 r11;
  uint64 r12;
  uint64 r13;
  uint64 r14;
  uint64 r15;
  uint64 rdi;
  uint64 rsi;
  uint64 rbp;
  uint64 rbx;
  uint64 rdx;
  uint64 rax;
  uint64 rcx;
  uint64 rsp;
  uint64 rip;
  uint64 eflags;           /* RFLAGS */
  uint16 cs;
  uint16 gs;
  uint16 fs;
  uint16 __pad0;
  uint64 err;
  uint64 trapno;
  uint64 oldmask;
  uint64 cr2;
  struct _fpstate *fpstate;       /* zero when no FPU context */
  uint64 reserved1[8];
};


/* From /usr/include/asm-x86_64/signal.h */
typedef struct sigaltstack {
	void /*__user*/ *ss_sp;
	int32 ss_flags;
	uint64 ss_size;
} stack_t;

typedef uint64 sigset_t;


/* From /usr/include/asm-x86_64/ucontext.h */
struct ucontext {
  uint64            uc_flags;
  struct ucontext  *uc_link;
  stack_t           uc_stack;
  struct sigcontext uc_mcontext;
  sigset_t          uc_sigmask;   /* mask last for extensibility */
};


void
print_sigcontext(struct sigcontext *sc)
{
	prints("\nrax     ");  sys·printhex(sc->rax);
	prints("\nrbx     ");  sys·printhex(sc->rbx);
	prints("\nrcx     ");  sys·printhex(sc->rcx);
	prints("\nrdx     ");  sys·printhex(sc->rdx);
	prints("\nrdi     ");  sys·printhex(sc->rdi);
	prints("\nrsi     ");  sys·printhex(sc->rsi);
	prints("\nrbp     ");  sys·printhex(sc->rbp);
	prints("\nrsp     ");  sys·printhex(sc->rsp);
	prints("\nr8      ");  sys·printhex(sc->r8 );
	prints("\nr9      ");  sys·printhex(sc->r9 );
	prints("\nr10     ");  sys·printhex(sc->r10);
	prints("\nr11     ");  sys·printhex(sc->r11);
	prints("\nr12     ");  sys·printhex(sc->r12);
	prints("\nr13     ");  sys·printhex(sc->r13);
	prints("\nr14     ");  sys·printhex(sc->r14);
	prints("\nr15     ");  sys·printhex(sc->r15);
	prints("\nrip     ");  sys·printhex(sc->rip);
	prints("\nrflags  ");  sys·printhex(sc->eflags);
	prints("\ncs      ");  sys·printhex(sc->cs);
	prints("\nfs      ");  sys·printhex(sc->fs);
	prints("\ngs      ");  sys·printhex(sc->gs);
	prints("\n");
}


/*
 * This assembler routine takes the args from registers, puts them on the stack,
 * and calls sighandler().
 */
extern void sigtramp(void);
extern void sigignore(void);	// just returns
extern void sigreturn(void);	// calls sigreturn

/*
 * Rudimentary reverse-engineered definition of signal interface.
 * You'd think it would be documented.
 */
/* From /usr/include/bits/siginfo.h */
struct siginfo {
	int32	si_signo;		/* signal number */
	int32	si_errno;		/* errno association */
	int32	si_code;		/* signal code */
	int32	si_status;		/* exit value */
	void	*si_addr;		/* faulting address */
	/* more stuff here */
};

// This is a struct sigaction from /usr/include/asm/signal.h
struct sigaction {
	void (*sa_handler)(int32, struct siginfo*, void*);
	uint64 sa_flags;
	void (*sa_restorer)(void);
	uint64 sa_mask;
};

void
sighandler(int32 sig, struct siginfo* info, void** context)
{
	if(panicking)	// traceback already printed
		sys_Exit(2);

	struct sigcontext *sc = &(((struct ucontext *)context)->uc_mcontext);

	if(sig < 0 || sig >= NSIG){
		prints("Signal ");
		sys·printint(sig);
	}else{
		prints(sigtab[sig].name);
	}

	prints("\nFaulting address: ");  sys·printpointer(info->si_addr);
	prints("\npc: ");  sys·printhex(sc->rip);
	prints("\n\n");

	if(gotraceback()){
		traceback((void *)sc->rip, (void *)sc->rsp, (void *)sc->r15);
		tracebackothers((void*)sc->r15);
		print_sigcontext(sc);
	}

	sys·Breakpoint();
	sys_Exit(2);
}

struct stack_t {
	void *sp;
	int32 flags;
	int32 pad;
	int64 size;
};

void
signalstack(byte *p, int32 n)
{
	struct stack_t st;

	st.sp = p;
	st.size = n;
	st.pad = 0;
	st.flags = 0;
	sigaltstack(&st, nil);
}

void	rt_sigaction(int64, void*, void*, uint64);

enum {
	SA_RESTART = 0x10000000,
	SA_ONSTACK = 0x08000000,
	SA_RESTORER = 0x04000000,
	SA_SIGINFO = 0x00000004,
};

void
initsig(void)
{
	static struct sigaction sa;

	int32 i;
	sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
	sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
	sa.sa_restorer = (void*)sigreturn;
	for(i = 0; i<NSIG; i++) {
		if(sigtab[i].flags) {
			if(sigtab[i].flags & SigCatch)
				sa.sa_handler = (void*)sigtramp;
			else
				sa.sa_handler = (void*)sigignore;
			if(sigtab[i].flags & SigRestart)
				sa.sa_flags |= SA_RESTART;
			else
				sa.sa_flags &= ~SA_RESTART;
			rt_sigaction(i, &sa, nil, 8);
		}
	}
}