1// Copyright 2010 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime
6
7import (
8	"internal/abi"
9	"internal/goarch"
10	"internal/stringslite"
11	"unsafe"
12)
13
14// May run during STW, so write barriers are not allowed.
15//
16//go:nowritebarrierrec
17func sighandler(_ureg *ureg, note *byte, gp *g) int {
18	gsignal := getg()
19	mp := gsignal.m
20
21	var t sigTabT
22	var docrash bool
23	var sig int
24	var flags int
25	var level int32
26
27	c := &sigctxt{_ureg}
28	notestr := gostringnocopy(note)
29
30	// The kernel will never pass us a nil note or ureg so we probably
31	// made a mistake somewhere in sigtramp.
32	if _ureg == nil || note == nil {
33		print("sighandler: ureg ", _ureg, " note ", note, "\n")
34		goto Throw
35	}
36	// Check that the note is no more than ERRMAX bytes (including
37	// the trailing NUL). We should never receive a longer note.
38	if len(notestr) > _ERRMAX-1 {
39		print("sighandler: note is longer than ERRMAX\n")
40		goto Throw
41	}
42	if isAbortPC(c.pc()) {
43		// Never turn abort into a panic.
44		goto Throw
45	}
46	// See if the note matches one of the patterns in sigtab.
47	// Notes that do not match any pattern can be handled at a higher
48	// level by the program but will otherwise be ignored.
49	flags = _SigNotify
50	for sig, t = range sigtable {
51		if stringslite.HasPrefix(notestr, t.name) {
52			flags = t.flags
53			break
54		}
55	}
56	if flags&_SigPanic != 0 && gp.throwsplit {
57		// We can't safely sigpanic because it may grow the
58		// stack. Abort in the signal handler instead.
59		flags = (flags &^ _SigPanic) | _SigThrow
60	}
61	if flags&_SigGoExit != 0 {
62		exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix.
63	}
64	if flags&_SigPanic != 0 {
65		// Copy the error string from sigtramp's stack into m->notesig so
66		// we can reliably access it from the panic routines.
67		memmove(unsafe.Pointer(mp.notesig), unsafe.Pointer(note), uintptr(len(notestr)+1))
68		gp.sig = uint32(sig)
69		gp.sigpc = c.pc()
70
71		pc := c.pc()
72		sp := c.sp()
73
74		// If we don't recognize the PC as code
75		// but we do recognize the top pointer on the stack as code,
76		// then assume this was a call to non-code and treat like
77		// pc == 0, to make unwinding show the context.
78		if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
79			pc = 0
80		}
81
82		// IF LR exists, sigpanictramp must save it to the stack
83		// before entry to sigpanic so that panics in leaf
84		// functions are correctly handled. This will smash
85		// the stack frame but we're not going back there
86		// anyway.
87		if usesLR {
88			c.savelr(c.lr())
89		}
90
91		// If PC == 0, probably panicked because of a call to a nil func.
92		// Not faking that as the return address will make the trace look like a call
93		// to sigpanic instead. (Otherwise the trace will end at
94		// sigpanic and we won't get to see who faulted).
95		if pc != 0 {
96			if usesLR {
97				c.setlr(pc)
98			} else {
99				sp -= goarch.PtrSize
100				*(*uintptr)(unsafe.Pointer(sp)) = pc
101				c.setsp(sp)
102			}
103		}
104		if usesLR {
105			c.setpc(abi.FuncPCABI0(sigpanictramp))
106		} else {
107			c.setpc(abi.FuncPCABI0(sigpanic0))
108		}
109		return _NCONT
110	}
111	if flags&_SigNotify != 0 {
112		if ignoredNote(note) {
113			return _NCONT
114		}
115		if sendNote(note) {
116			return _NCONT
117		}
118	}
119	if flags&_SigKill != 0 {
120		goto Exit
121	}
122	if flags&_SigThrow == 0 {
123		return _NCONT
124	}
125Throw:
126	mp.throwing = throwTypeRuntime
127	mp.caughtsig.set(gp)
128	startpanic_m()
129	print(notestr, "\n")
130	print("PC=", hex(c.pc()), "\n")
131	print("\n")
132	level, _, docrash = gotraceback()
133	if level > 0 {
134		goroutineheader(gp)
135		tracebacktrap(c.pc(), c.sp(), c.lr(), gp)
136		tracebackothers(gp)
137		print("\n")
138		dumpregs(_ureg)
139	}
140	if docrash {
141		crash()
142	}
143Exit:
144	goexitsall(note)
145	exits(note)
146	return _NDFLT // not reached
147}
148
149func sigenable(sig uint32) {
150}
151
152func sigdisable(sig uint32) {
153}
154
155func sigignore(sig uint32) {
156}
157
158func setProcessCPUProfiler(hz int32) {
159}
160
161func setThreadCPUProfiler(hz int32) {
162	// TODO: Enable profiling interrupts.
163	getg().m.profilehz = hz
164}
165
166// gsignalStack is unused on Plan 9.
167type gsignalStack struct{}
168