|  | // Copyright 2022 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. | 
|  |  | 
|  | //go:build amd64 && linux | 
|  |  | 
|  | package runtime | 
|  |  | 
|  | import ( | 
|  | "internal/abi" | 
|  | "internal/goarch" | 
|  | "unsafe" | 
|  | ) | 
|  |  | 
|  | type sigContext struct { | 
|  | savedRegs sigcontext | 
|  | // sigcontext.fpstate is a pointer, so we need to save | 
|  | // the its value with a fpstate1 structure. | 
|  | savedFP fpstate1 | 
|  | } | 
|  |  | 
|  | func sigctxtSetContextRegister(ctxt *sigctxt, x uint64) { | 
|  | ctxt.regs().rdx = x | 
|  | } | 
|  |  | 
|  | func sigctxtAtTrapInstruction(ctxt *sigctxt) bool { | 
|  | return *(*byte)(unsafe.Pointer(uintptr(ctxt.rip() - 1))) == 0xcc // INT 3 | 
|  | } | 
|  |  | 
|  | func sigctxtStatus(ctxt *sigctxt) uint64 { | 
|  | return ctxt.r12() | 
|  | } | 
|  |  | 
|  | func (h *debugCallHandler) saveSigContext(ctxt *sigctxt) { | 
|  | // Push current PC on the stack. | 
|  | rsp := ctxt.rsp() - goarch.PtrSize | 
|  | *(*uint64)(unsafe.Pointer(uintptr(rsp))) = ctxt.rip() | 
|  | ctxt.set_rsp(rsp) | 
|  | // Write the argument frame size. | 
|  | *(*uintptr)(unsafe.Pointer(uintptr(rsp - 16))) = h.argSize | 
|  | // Save current registers. | 
|  | h.sigCtxt.savedRegs = *ctxt.regs() | 
|  | h.sigCtxt.savedFP = *h.sigCtxt.savedRegs.fpstate | 
|  | h.sigCtxt.savedRegs.fpstate = nil | 
|  | } | 
|  |  | 
|  | // case 0 | 
|  | func (h *debugCallHandler) debugCallRun(ctxt *sigctxt) { | 
|  | rsp := ctxt.rsp() | 
|  | memmove(unsafe.Pointer(uintptr(rsp)), h.argp, h.argSize) | 
|  | if h.regArgs != nil { | 
|  | storeRegArgs(ctxt.regs(), h.regArgs) | 
|  | } | 
|  | // Push return PC. | 
|  | rsp -= goarch.PtrSize | 
|  | ctxt.set_rsp(rsp) | 
|  | // The signal PC is the next PC of the trap instruction. | 
|  | *(*uint64)(unsafe.Pointer(uintptr(rsp))) = ctxt.rip() | 
|  | // Set PC to call and context register. | 
|  | ctxt.set_rip(uint64(h.fv.fn)) | 
|  | sigctxtSetContextRegister(ctxt, uint64(uintptr(unsafe.Pointer(h.fv)))) | 
|  | } | 
|  |  | 
|  | // case 1 | 
|  | func (h *debugCallHandler) debugCallReturn(ctxt *sigctxt) { | 
|  | rsp := ctxt.rsp() | 
|  | memmove(h.argp, unsafe.Pointer(uintptr(rsp)), h.argSize) | 
|  | if h.regArgs != nil { | 
|  | loadRegArgs(h.regArgs, ctxt.regs()) | 
|  | } | 
|  | } | 
|  |  | 
|  | // case 2 | 
|  | func (h *debugCallHandler) debugCallPanicOut(ctxt *sigctxt) { | 
|  | rsp := ctxt.rsp() | 
|  | memmove(unsafe.Pointer(&h.panic), unsafe.Pointer(uintptr(rsp)), 2*goarch.PtrSize) | 
|  | } | 
|  |  | 
|  | // case 8 | 
|  | func (h *debugCallHandler) debugCallUnsafe(ctxt *sigctxt) { | 
|  | rsp := ctxt.rsp() | 
|  | reason := *(*string)(unsafe.Pointer(uintptr(rsp))) | 
|  | h.err = plainError(reason) | 
|  | } | 
|  |  | 
|  | // case 16 | 
|  | func (h *debugCallHandler) restoreSigContext(ctxt *sigctxt) { | 
|  | // Restore all registers except RIP and RSP. | 
|  | rip, rsp := ctxt.rip(), ctxt.rsp() | 
|  | fp := ctxt.regs().fpstate | 
|  | *ctxt.regs() = h.sigCtxt.savedRegs | 
|  | ctxt.regs().fpstate = fp | 
|  | *fp = h.sigCtxt.savedFP | 
|  | ctxt.set_rip(rip) | 
|  | ctxt.set_rsp(rsp) | 
|  | } | 
|  |  | 
|  | // storeRegArgs sets up argument registers in the signal | 
|  | // context state from an abi.RegArgs. | 
|  | // | 
|  | // Both src and dst must be non-nil. | 
|  | func storeRegArgs(dst *sigcontext, src *abi.RegArgs) { | 
|  | dst.rax = uint64(src.Ints[0]) | 
|  | dst.rbx = uint64(src.Ints[1]) | 
|  | dst.rcx = uint64(src.Ints[2]) | 
|  | dst.rdi = uint64(src.Ints[3]) | 
|  | dst.rsi = uint64(src.Ints[4]) | 
|  | dst.r8 = uint64(src.Ints[5]) | 
|  | dst.r9 = uint64(src.Ints[6]) | 
|  | dst.r10 = uint64(src.Ints[7]) | 
|  | dst.r11 = uint64(src.Ints[8]) | 
|  | for i := range src.Floats { | 
|  | dst.fpstate._xmm[i].element[0] = uint32(src.Floats[i] >> 0) | 
|  | dst.fpstate._xmm[i].element[1] = uint32(src.Floats[i] >> 32) | 
|  | } | 
|  | } | 
|  |  | 
|  | func loadRegArgs(dst *abi.RegArgs, src *sigcontext) { | 
|  | dst.Ints[0] = uintptr(src.rax) | 
|  | dst.Ints[1] = uintptr(src.rbx) | 
|  | dst.Ints[2] = uintptr(src.rcx) | 
|  | dst.Ints[3] = uintptr(src.rdi) | 
|  | dst.Ints[4] = uintptr(src.rsi) | 
|  | dst.Ints[5] = uintptr(src.r8) | 
|  | dst.Ints[6] = uintptr(src.r9) | 
|  | dst.Ints[7] = uintptr(src.r10) | 
|  | dst.Ints[8] = uintptr(src.r11) | 
|  | for i := range dst.Floats { | 
|  | dst.Floats[i] = uint64(src.fpstate._xmm[i].element[0]) << 0 | 
|  | dst.Floats[i] |= uint64(src.fpstate._xmm[i].element[1]) << 32 | 
|  | } | 
|  | } |