--- /dev/null
+// Copyright 2025 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.
+
+// Architecture-independent definitions.
+
+package windows
+
+// Pseudo handles.
+const (
+ CurrentProcess = ^uintptr(0) // -1 = current process
+ CurrentThread = ^uintptr(1) // -2 = current thread
+)
+
+const INVALID_HANDLE_VALUE = ^uintptr(0)
+
+const DWORD_MAX = 0xffffffff
+
+const (
+ PROT_NONE = 0
+ PROT_READ = 1
+ PROT_WRITE = 2
+ PROT_EXEC = 4
+)
+
+const (
+ MAP_ANON = 1
+ MAP_PRIVATE = 2
+)
+
+const DUPLICATE_SAME_ACCESS = 0x2
+
+const THREAD_PRIORITY_HIGHEST = 0x2
+
+const (
+ SIGINT = 0x2
+ SIGTERM = 0xF
+)
+
+const (
+ CTRL_C_EVENT = 0x0
+ CTRL_BREAK_EVENT = 0x1
+ CTRL_CLOSE_EVENT = 0x2
+ CTRL_LOGOFF_EVENT = 0x5
+ CTRL_SHUTDOWN_EVENT = 0x6
+)
+
+const (
+ EXCEPTION_ACCESS_VIOLATION = 0xc0000005
+ EXCEPTION_IN_PAGE_ERROR = 0xc0000006
+ EXCEPTION_BREAKPOINT = 0x80000003
+ EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d
+ EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d
+ EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e
+ EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f
+ EXCEPTION_FLT_OVERFLOW = 0xc0000091
+ EXCEPTION_FLT_UNDERFLOW = 0xc0000093
+ EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094
+ EXCEPTION_INT_OVERFLOW = 0xc0000095
+)
+
+const (
+ SEM_FAILCRITICALERRORS = 0x0001
+ SEM_NOGPFAULTERRORBOX = 0x0002
+ SEM_NOOPENFILEERRORBOX = 0x8000
+)
+
+const WER_FAULT_REPORTING_NO_UI = 0x0020
+
+const INFINITE = 0xffffffff
+
+const WAIT_TIMEOUT = 258
+
+const FAIL_FAST_GENERATE_EXCEPTION_ADDRESS = 0x1
+
+const (
+ EXCEPTION_CONTINUE_EXECUTION = -0x1
+ EXCEPTION_CONTINUE_SEARCH = 0x0
+ EXCEPTION_CONTINUE_SEARCH_SEH = 0x1
+)
+
+const CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002
+
+const (
+ SYNCHRONIZE = 0x00100000
+ TIMER_QUERY_STATE = 0x0001
+ TIMER_MODIFY_STATE = 0x0002
+)
+
+// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
+const (
+ STATUS_SUCCESS = 0x00000000
+ STATUS_PENDING = 0x00000103
+ STATUS_CANCELLED = 0xC0000120
+)
+
+// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
+type SystemInfo struct {
+ ProcessorArchitecture uint16
+ Reserved uint16
+ PageSize uint32
+ MinimumApplicationAddress *byte
+ MaximumApplicationAddress *byte
+ ActiveProcessorMask uintptr
+ NumberOfProcessors uint32
+ ProcessorType uint32
+ AllocationGranularity uint32
+ ProcessorLevel uint16
+ ProcessorRevision uint16
+}
+
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_pointers
+type ExceptionPointers struct {
+ Record *ExceptionRecord
+ Context *Context
+}
+
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
+type ExceptionRecord struct {
+ ExceptionCode uint32
+ ExceptionFlags uint32
+ ExceptionRecord *ExceptionRecord
+ ExceptionAddress uintptr
+ NumberParameters uint32
+ ExceptionInformation [15]uintptr
+}
+
+type Handle uintptr
+
+// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped
+type Overlapped struct {
+ Internal uintptr
+ InternalHigh uintptr
+ Offset uint32
+ OffsetHigh uint32
+ HEvent Handle
+}
+
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information
+type MemoryBasicInformation struct {
+ BaseAddress uintptr
+ AllocationBase uintptr
+ AllocationProtect uint32
+ PartitionId uint16
+ RegionSize uintptr
+ State uint32
+ Protect uint32
+ Type uint32
+}
+
+// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
+type OSVERSIONINFOW struct {
+ OSVersionInfoSize uint32
+ MajorVersion uint32
+ MinorVersion uint32
+ BuildNumber uint32
+ PlatformID uint32
+ CSDVersion [128]uint16
+}
--- /dev/null
+// Copyright 2025 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.
+
+package windows
+
+import (
+ "internal/goarch"
+ "unsafe"
+)
+
+const CONTEXT_CONTROL = 0x10001
+
+type FloatingSaveArea struct {
+ ControlWord uint32
+ StatusWord uint32
+ TagWord uint32
+ ErrorOffset uint32
+ ErrorSelector uint32
+ DataOffset uint32
+ DataSelector uint32
+ RegisterArea [80]uint8
+ Cr0NpxState uint32
+}
+
+type Context struct {
+ ContextFlags uint32
+ Dr0 uint32
+ Dr1 uint32
+ Dr2 uint32
+ Dr3 uint32
+ Dr6 uint32
+ Dr7 uint32
+ FloatingSaveArea FloatingSaveArea
+ SegGs uint32
+ SegFs uint32
+ SegEs uint32
+ SegDs uint32
+ Edi uint32
+ Esi uint32
+ Ebx uint32
+ Edx uint32
+ Ecx uint32
+ Eax uint32
+ Ebp uint32
+ Eip uint32
+ SegCs uint32
+ EFlags uint32
+ Esp uint32
+ SegSs uint32
+ ExtendedRegisters [512]uint8
+}
+
+func (c *Context) PC() uintptr { return uintptr(c.Eip) }
+func (c *Context) SP() uintptr { return uintptr(c.Esp) }
+
+// 386 does not have link register, so this returns 0.
+func (c *Context) LR() uintptr { return 0 }
+func (c *Context) SetLR(x uintptr) {}
+
+func (c *Context) SetPC(x uintptr) { c.Eip = uint32(x) }
+func (c *Context) SetSP(x uintptr) { c.Esp = uint32(x) }
+
+// 386 does not have frame pointer register.
+func (c *Context) SetFP(x uintptr) {}
+
+func (c *Context) PushCall(targetPC, resumePC uintptr) {
+ sp := c.SP() - goarch.StackAlign
+ *(*uintptr)(unsafe.Pointer(sp)) = resumePC
+ c.SetSP(sp)
+ c.SetPC(targetPC)
+}
+
+// DISPATCHER_CONTEXT is not defined on 386.
+type DISPATCHER_CONTEXT struct{}
+
+func (c *DISPATCHER_CONTEXT) Ctx() *Context {
+ return nil
+}
--- /dev/null
+// Copyright 2025 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.
+
+package windows
+
+import (
+ "internal/goarch"
+ "unsafe"
+)
+
+const CONTEXT_CONTROL = 0x100001
+
+type M128 struct {
+ Low uint64
+ High int64
+}
+
+type Context struct {
+ P1Home uint64
+ P2Home uint64
+ P3Home uint64
+ P4Home uint64
+ P5Home uint64
+ P6Home uint64
+ ContextFlags uint32
+ MxCsr uint32
+ SegCs uint16
+ SegDs uint16
+ SegEs uint16
+ SegFs uint16
+ SegGs uint16
+ SegSs uint16
+ EFlags uint32
+ DR0 uint64
+ DR1 uint64
+ DR2 uint64
+ DR3 uint64
+ DR6 uint64
+ DR7 uint64
+ Rax uint64
+ Rcx uint64
+ Rdx uint64
+ Rbx uint64
+ Rsp uint64
+ Rbp uint64
+ Rsi uint64
+ Rdi uint64
+ R8 uint64
+ R9 uint64
+ R10 uint64
+ R11 uint64
+ R12 uint64
+ R13 uint64
+ R14 uint64
+ R15 uint64
+ Rip uint64
+ _ [512]byte
+ VectorRegister [26]M128
+ VectorControl uint64
+ DebugControl uint64
+ LastBranchToRip uint64
+ LastBranchFromRip uint64
+ LastExceptionToRip uint64
+ LastExceptionFromRip uint64
+}
+
+func (c *Context) PC() uintptr { return uintptr(c.Rip) }
+func (c *Context) SP() uintptr { return uintptr(c.Rsp) }
+
+// AMD64 does not have link register, so this returns 0.
+func (c *Context) LR() uintptr { return 0 }
+func (c *Context) SetLR(x uintptr) {}
+
+func (c *Context) SetPC(x uintptr) { c.Rip = uint64(x) }
+func (c *Context) SetSP(x uintptr) { c.Rsp = uint64(x) }
+func (c *Context) SetFP(x uintptr) { c.Rbp = uint64(x) }
+
+func (c *Context) PushCall(targetPC, resumePC uintptr) {
+ sp := c.SP() - goarch.StackAlign
+ *(*uintptr)(unsafe.Pointer(sp)) = resumePC
+ c.SetSP(sp)
+ c.SetPC(targetPC)
+}
+
+type DISPATCHER_CONTEXT struct {
+ ControlPc uint64
+ ImageBase uint64
+ FunctionEntry uintptr
+ EstablisherFrame uint64
+ TargetIp uint64
+ Context *Context
+ LanguageHandler uintptr
+ HandlerData uintptr
+}
+
+func (c *DISPATCHER_CONTEXT) Ctx() *Context {
+ return c.Context
+}
--- /dev/null
+// Copyright 2025 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.
+
+package windows
+
+import (
+ "internal/goarch"
+ "unsafe"
+)
+
+// NOTE(rsc): CONTEXT_CONTROL is actually 0x400001 and should include PC, SP, and LR.
+// However, empirically, LR doesn't come along on Windows 10
+// unless you also set CONTEXT_INTEGER (0x400002).
+// Without LR, we skip over the next-to-bottom function in profiles
+// when the bottom function is frameless.
+// So we set both here, to make a working CONTEXT_CONTROL.
+const CONTEXT_CONTROL = 0x400003
+
+type Neon128 struct {
+ Low uint64
+ High int64
+}
+
+// See https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-arm64_nt_context
+type Context struct {
+ ContextFlags uint32
+ Cpsr uint32
+ X [31]uint64 // fp is x[29], lr is x[30]
+ XSp uint64
+ Pc uint64
+ V [32]Neon128
+ Fpcr uint32
+ Fpsr uint32
+ Bcr [8]uint32
+ Bvr [8]uint64
+ Wcr [2]uint32
+ Wvr [2]uint64
+}
+
+func (c *Context) PC() uintptr { return uintptr(c.Pc) }
+func (c *Context) SP() uintptr { return uintptr(c.XSp) }
+func (c *Context) LR() uintptr { return uintptr(c.X[30]) }
+
+func (c *Context) SetPC(x uintptr) { c.Pc = uint64(x) }
+func (c *Context) SetSP(x uintptr) { c.XSp = uint64(x) }
+func (c *Context) SetLR(x uintptr) { c.X[30] = uint64(x) }
+func (c *Context) SetFP(x uintptr) { c.X[29] = uint64(x) }
+
+func (c *Context) PushCall(targetPC, resumePC uintptr) {
+ // Push LR. The injected call is responsible
+ // for restoring LR. gentraceback is aware of
+ // this extra slot. See sigctxt.pushCall in
+ // signal_arm64.go.
+ sp := c.SP() - goarch.StackAlign
+ c.SetSP(sp)
+ *(*uint64)(unsafe.Pointer(sp)) = uint64(c.LR())
+ c.SetLR(resumePC)
+ c.SetPC(targetPC)
+}
+
+type DISPATCHER_CONTEXT struct {
+ ControlPc uint64
+ ImageBase uint64
+ FunctionEntry uintptr
+ EstablisherFrame uint64
+ TargetIp uint64
+ Context *Context
+ LanguageHandler uintptr
+ HandlerData uintptr
+}
+
+func (c *DISPATCHER_CONTEXT) Ctx() *Context {
+ return c.Context
+}
+++ /dev/null
-// Copyright 2017 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.
-
-package windows
-
-type MemoryBasicInformation struct {
- // A pointer to the base address of the region of pages.
- BaseAddress uintptr
- // A pointer to the base address of a range of pages allocated by the VirtualAlloc function.
- // The page pointed to by the BaseAddress member is contained within this allocation range.
- AllocationBase uintptr
- // The memory protection option when the region was initially allocated
- AllocationProtect uint32
- PartitionId uint16
- // The size of the region beginning at the base address in which all pages have identical attributes, in bytes.
- RegionSize uintptr
- // The state of the pages in the region.
- State uint32
- // The access protection of the pages in the region.
- Protect uint32
- // The type of pages in the region.
- Type uint32
-}
package windows
import (
+ "internal/runtime/syscall/windows"
"syscall"
"unsafe"
)
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
const VER_NT_WORKSTATION = 0x0000001
+
+type MemoryBasicInformation = windows.MemoryBasicInformation
+
+type Context = windows.Context
+++ /dev/null
-// 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.
-
-// Windows architecture-independent definitions.
-
-package runtime
-
-const (
- _PROT_NONE = 0
- _PROT_READ = 1
- _PROT_WRITE = 2
- _PROT_EXEC = 4
-
- _MAP_ANON = 1
- _MAP_PRIVATE = 2
-
- _DUPLICATE_SAME_ACCESS = 0x2
- _THREAD_PRIORITY_HIGHEST = 0x2
-
- _SIGINT = 0x2
- _SIGTERM = 0xF
- _CTRL_C_EVENT = 0x0
- _CTRL_BREAK_EVENT = 0x1
- _CTRL_CLOSE_EVENT = 0x2
- _CTRL_LOGOFF_EVENT = 0x5
- _CTRL_SHUTDOWN_EVENT = 0x6
-
- _EXCEPTION_ACCESS_VIOLATION = 0xc0000005
- _EXCEPTION_IN_PAGE_ERROR = 0xc0000006
- _EXCEPTION_BREAKPOINT = 0x80000003
- _EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d
- _EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d
- _EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e
- _EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f
- _EXCEPTION_FLT_OVERFLOW = 0xc0000091
- _EXCEPTION_FLT_UNDERFLOW = 0xc0000093
- _EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094
- _EXCEPTION_INT_OVERFLOW = 0xc0000095
-
- _INFINITE = 0xffffffff
- _WAIT_TIMEOUT = 0x102
-
- _EXCEPTION_CONTINUE_EXECUTION = -0x1
- _EXCEPTION_CONTINUE_SEARCH = 0x0
- _EXCEPTION_CONTINUE_SEARCH_SEH = 0x1
-)
-
-type systeminfo struct {
- anon0 [4]byte
- dwpagesize uint32
- lpminimumapplicationaddress *byte
- lpmaximumapplicationaddress *byte
- dwactiveprocessormask uintptr
- dwnumberofprocessors uint32
- dwprocessortype uint32
- dwallocationgranularity uint32
- wprocessorlevel uint16
- wprocessorrevision uint16
-}
-
-type exceptionpointers struct {
- record *exceptionrecord
- context *context
-}
-
-type exceptionrecord struct {
- exceptioncode uint32
- exceptionflags uint32
- exceptionrecord *exceptionrecord
- exceptionaddress uintptr
- numberparameters uint32
- exceptioninformation [15]uintptr
-}
-
-type overlapped struct {
- internal uintptr
- internalhigh uintptr
- anon0 [8]byte
- hevent *byte
-}
-
-type memoryBasicInformation struct {
- baseAddress uintptr
- allocationBase uintptr
- allocationProtect uint32
- regionSize uintptr
- state uint32
- protect uint32
- type_ uint32
-}
-
-// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
-type _OSVERSIONINFOW struct {
- osVersionInfoSize uint32
- majorVersion uint32
- minorVersion uint32
- buildNumber uint32
- platformId uint32
- csdVersion [128]uint16
-}
+++ /dev/null
-// 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.
-
-package runtime
-
-import (
- "internal/goarch"
- "unsafe"
-)
-
-const _CONTEXT_CONTROL = 0x10001
-
-type floatingsavearea struct {
- controlword uint32
- statusword uint32
- tagword uint32
- erroroffset uint32
- errorselector uint32
- dataoffset uint32
- dataselector uint32
- registerarea [80]uint8
- cr0npxstate uint32
-}
-
-type context struct {
- contextflags uint32
- dr0 uint32
- dr1 uint32
- dr2 uint32
- dr3 uint32
- dr6 uint32
- dr7 uint32
- floatsave floatingsavearea
- seggs uint32
- segfs uint32
- seges uint32
- segds uint32
- edi uint32
- esi uint32
- ebx uint32
- edx uint32
- ecx uint32
- eax uint32
- ebp uint32
- eip uint32
- segcs uint32
- eflags uint32
- esp uint32
- segss uint32
- extendedregisters [512]uint8
-}
-
-func (c *context) ip() uintptr { return uintptr(c.eip) }
-func (c *context) sp() uintptr { return uintptr(c.esp) }
-
-// 386 does not have link register, so this returns 0.
-func (c *context) lr() uintptr { return 0 }
-func (c *context) set_lr(x uintptr) {}
-
-func (c *context) set_ip(x uintptr) { c.eip = uint32(x) }
-func (c *context) set_sp(x uintptr) { c.esp = uint32(x) }
-
-// 386 does not have frame pointer register.
-func (c *context) set_fp(x uintptr) {}
-
-func (c *context) pushCall(targetPC, resumePC uintptr) {
- sp := c.sp() - goarch.StackAlign
- *(*uintptr)(unsafe.Pointer(sp)) = resumePC
- c.set_sp(sp)
- c.set_ip(targetPC)
-}
-
-func prepareContextForSigResume(c *context) {
- c.edx = c.esp
- c.ecx = c.eip
-}
-
-func dumpregs(r *context) {
- print("eax ", hex(r.eax), "\n")
- print("ebx ", hex(r.ebx), "\n")
- print("ecx ", hex(r.ecx), "\n")
- print("edx ", hex(r.edx), "\n")
- print("edi ", hex(r.edi), "\n")
- print("esi ", hex(r.esi), "\n")
- print("ebp ", hex(r.ebp), "\n")
- print("esp ", hex(r.esp), "\n")
- print("eip ", hex(r.eip), "\n")
- print("eflags ", hex(r.eflags), "\n")
- print("cs ", hex(r.segcs), "\n")
- print("fs ", hex(r.segfs), "\n")
- print("gs ", hex(r.seggs), "\n")
-}
-
-// _DISPATCHER_CONTEXT is not defined on 386.
-type _DISPATCHER_CONTEXT struct{}
-
-func (c *_DISPATCHER_CONTEXT) ctx() *context {
- return nil
-}
+++ /dev/null
-// 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.
-
-package runtime
-
-import (
- "internal/goarch"
- "unsafe"
-)
-
-const _CONTEXT_CONTROL = 0x100001
-
-type m128a struct {
- low uint64
- high int64
-}
-
-type context struct {
- p1home uint64
- p2home uint64
- p3home uint64
- p4home uint64
- p5home uint64
- p6home uint64
- contextflags uint32
- mxcsr uint32
- segcs uint16
- segds uint16
- seges uint16
- segfs uint16
- seggs uint16
- segss uint16
- eflags uint32
- dr0 uint64
- dr1 uint64
- dr2 uint64
- dr3 uint64
- dr6 uint64
- dr7 uint64
- rax uint64
- rcx uint64
- rdx uint64
- rbx uint64
- rsp uint64
- rbp uint64
- rsi uint64
- rdi uint64
- r8 uint64
- r9 uint64
- r10 uint64
- r11 uint64
- r12 uint64
- r13 uint64
- r14 uint64
- r15 uint64
- rip uint64
- anon0 [512]byte
- vectorregister [26]m128a
- vectorcontrol uint64
- debugcontrol uint64
- lastbranchtorip uint64
- lastbranchfromrip uint64
- lastexceptiontorip uint64
- lastexceptionfromrip uint64
-}
-
-func (c *context) ip() uintptr { return uintptr(c.rip) }
-func (c *context) sp() uintptr { return uintptr(c.rsp) }
-
-// AMD64 does not have link register, so this returns 0.
-func (c *context) lr() uintptr { return 0 }
-func (c *context) set_lr(x uintptr) {}
-
-func (c *context) set_ip(x uintptr) { c.rip = uint64(x) }
-func (c *context) set_sp(x uintptr) { c.rsp = uint64(x) }
-func (c *context) set_fp(x uintptr) { c.rbp = uint64(x) }
-
-func (c *context) pushCall(targetPC, resumePC uintptr) {
- sp := c.sp() - goarch.StackAlign
- *(*uintptr)(unsafe.Pointer(sp)) = resumePC
- c.set_sp(sp)
- c.set_ip(targetPC)
-}
-
-func prepareContextForSigResume(c *context) {
- c.r8 = c.rsp
- c.r9 = c.rip
-}
-
-func dumpregs(r *context) {
- print("rax ", hex(r.rax), "\n")
- print("rbx ", hex(r.rbx), "\n")
- print("rcx ", hex(r.rcx), "\n")
- print("rdx ", hex(r.rdx), "\n")
- print("rdi ", hex(r.rdi), "\n")
- print("rsi ", hex(r.rsi), "\n")
- print("rbp ", hex(r.rbp), "\n")
- print("rsp ", hex(r.rsp), "\n")
- print("r8 ", hex(r.r8), "\n")
- print("r9 ", hex(r.r9), "\n")
- print("r10 ", hex(r.r10), "\n")
- print("r11 ", hex(r.r11), "\n")
- print("r12 ", hex(r.r12), "\n")
- print("r13 ", hex(r.r13), "\n")
- print("r14 ", hex(r.r14), "\n")
- print("r15 ", hex(r.r15), "\n")
- print("rip ", hex(r.rip), "\n")
- print("rflags ", hex(r.eflags), "\n")
- print("cs ", hex(r.segcs), "\n")
- print("fs ", hex(r.segfs), "\n")
- print("gs ", hex(r.seggs), "\n")
-}
-
-type _DISPATCHER_CONTEXT struct {
- controlPc uint64
- imageBase uint64
- functionEntry uintptr
- establisherFrame uint64
- targetIp uint64
- context *context
- languageHandler uintptr
- handlerData uintptr
-}
-
-func (c *_DISPATCHER_CONTEXT) ctx() *context {
- return c.context
-}
+++ /dev/null
-// Copyright 2018 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.
-
-package runtime
-
-import (
- "internal/goarch"
- "unsafe"
-)
-
-// NOTE(rsc): _CONTEXT_CONTROL is actually 0x400001 and should include PC, SP, and LR.
-// However, empirically, LR doesn't come along on Windows 10
-// unless you also set _CONTEXT_INTEGER (0x400002).
-// Without LR, we skip over the next-to-bottom function in profiles
-// when the bottom function is frameless.
-// So we set both here, to make a working _CONTEXT_CONTROL.
-const _CONTEXT_CONTROL = 0x400003
-
-type neon128 struct {
- low uint64
- high int64
-}
-
-// See https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-arm64_nt_context
-type context struct {
- contextflags uint32
- cpsr uint32
- x [31]uint64 // fp is x[29], lr is x[30]
- xsp uint64
- pc uint64
- v [32]neon128
- fpcr uint32
- fpsr uint32
- bcr [8]uint32
- bvr [8]uint64
- wcr [2]uint32
- wvr [2]uint64
-}
-
-func (c *context) ip() uintptr { return uintptr(c.pc) }
-func (c *context) sp() uintptr { return uintptr(c.xsp) }
-func (c *context) lr() uintptr { return uintptr(c.x[30]) }
-
-func (c *context) set_ip(x uintptr) { c.pc = uint64(x) }
-func (c *context) set_sp(x uintptr) { c.xsp = uint64(x) }
-func (c *context) set_lr(x uintptr) { c.x[30] = uint64(x) }
-func (c *context) set_fp(x uintptr) { c.x[29] = uint64(x) }
-
-func (c *context) pushCall(targetPC, resumePC uintptr) {
- // Push LR. The injected call is responsible
- // for restoring LR. gentraceback is aware of
- // this extra slot. See sigctxt.pushCall in
- // signal_arm64.go.
- sp := c.sp() - goarch.StackAlign
- c.set_sp(sp)
- *(*uint64)(unsafe.Pointer(sp)) = uint64(c.lr())
- c.set_lr(resumePC)
- c.set_ip(targetPC)
-}
-
-func prepareContextForSigResume(c *context) {
- c.x[0] = c.xsp
- c.x[1] = c.pc
-}
-
-func dumpregs(r *context) {
- print("r0 ", hex(r.x[0]), "\n")
- print("r1 ", hex(r.x[1]), "\n")
- print("r2 ", hex(r.x[2]), "\n")
- print("r3 ", hex(r.x[3]), "\n")
- print("r4 ", hex(r.x[4]), "\n")
- print("r5 ", hex(r.x[5]), "\n")
- print("r6 ", hex(r.x[6]), "\n")
- print("r7 ", hex(r.x[7]), "\n")
- print("r8 ", hex(r.x[8]), "\n")
- print("r9 ", hex(r.x[9]), "\n")
- print("r10 ", hex(r.x[10]), "\n")
- print("r11 ", hex(r.x[11]), "\n")
- print("r12 ", hex(r.x[12]), "\n")
- print("r13 ", hex(r.x[13]), "\n")
- print("r14 ", hex(r.x[14]), "\n")
- print("r15 ", hex(r.x[15]), "\n")
- print("r16 ", hex(r.x[16]), "\n")
- print("r17 ", hex(r.x[17]), "\n")
- print("r18 ", hex(r.x[18]), "\n")
- print("r19 ", hex(r.x[19]), "\n")
- print("r20 ", hex(r.x[20]), "\n")
- print("r21 ", hex(r.x[21]), "\n")
- print("r22 ", hex(r.x[22]), "\n")
- print("r23 ", hex(r.x[23]), "\n")
- print("r24 ", hex(r.x[24]), "\n")
- print("r25 ", hex(r.x[25]), "\n")
- print("r26 ", hex(r.x[26]), "\n")
- print("r27 ", hex(r.x[27]), "\n")
- print("r28 ", hex(r.x[28]), "\n")
- print("r29 ", hex(r.x[29]), "\n")
- print("lr ", hex(r.x[30]), "\n")
- print("sp ", hex(r.xsp), "\n")
- print("pc ", hex(r.pc), "\n")
- print("cpsr ", hex(r.cpsr), "\n")
-}
-
-func stackcheck() {
- // TODO: not implemented on ARM
-}
-
-type _DISPATCHER_CONTEXT struct {
- controlPc uint64
- imageBase uint64
- functionEntry uintptr
- establisherFrame uint64
- targetIp uint64
- context *context
- languageHandler uintptr
- handlerData uintptr
-}
-
-func (c *_DISPATCHER_CONTEXT) ctx() *context {
- return c.context
-}
package runtime
import (
- "internal/runtime/sys"
+ "internal/runtime/syscall/windows"
"unsafe"
)
)
func NumberOfProcessors() int32 {
- var info systeminfo
+ var info windows.SystemInfo
stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
- return int32(info.dwnumberofprocessors)
+ return int32(info.NumberOfProcessors)
}
-type ContextStub struct {
- context
-}
-
-func (c ContextStub) GetPC() uintptr {
- return c.ip()
-}
-
-func NewContextStub() *ContextStub {
- var ctx context
- ctx.set_ip(sys.GetCallerPC())
- ctx.set_sp(sys.GetCallerSP())
- ctx.set_fp(getcallerfp())
- return &ContextStub{ctx}
+func GetCallerFp() uintptr {
+ return getcallerfp()
}
import (
"internal/goarch"
"internal/runtime/atomic"
+ "internal/runtime/syscall/windows"
"unsafe"
)
-const _DWORD_MAX = 0xffffffff
-
-const _INVALID_HANDLE_VALUE = ^uintptr(0)
-
// Sources are used to identify the event that created an overlapped entry.
// The source values are arbitrary. There is no risk of collision with user
// defined values because the only way to set the key of an overlapped entry
// Keep these in sync.
type pollOperation struct {
// used by windows
- _ overlapped
+ _ windows.Overlapped
// used by netpoll
pd *pollDesc
mode int32
// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped_entry
type overlappedEntry struct {
key uintptr
- ov *overlapped
+ ov *windows.Overlapped
internal uintptr
qty uint32
}
var (
- iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
+ iocphandle uintptr = windows.INVALID_HANDLE_VALUE // completion port io handle
netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak
)
func netpollinit() {
- iocphandle = stdcall(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX)
+ iocphandle = stdcall(_CreateIoCompletionPort, windows.INVALID_HANDLE_VALUE, 0, 0, windows.DWORD_MAX)
if iocphandle == 0 {
println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")")
throw("runtime: netpollinit failed")
// delay == 0: does not block, just polls
// delay > 0: block for up to that many nanoseconds
func netpoll(delay int64) (gList, int32) {
- if iocphandle == _INVALID_HANDLE_VALUE {
+ if iocphandle == windows.INVALID_HANDLE_VALUE {
return gList{}, 0
}
}
}
if delay < 0 {
- wait = _INFINITE
+ wait = windows.INFINITE
} else if delay == 0 {
wait = 0
} else if delay < 1e6 {
if stdcall(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
mp.blocked = false
errno := getlasterror()
- if errno == _WAIT_TIMEOUT {
+ if errno == windows.WAIT_TIMEOUT {
return gList{}, 0
}
println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
// netpollQueueTimer queues a timer to wake up the poller after the given delay.
// It returns true if the timer expired during this call.
func netpollQueueTimer(delay int64) (signaled bool) {
- const (
- STATUS_SUCCESS = 0x00000000
- STATUS_PENDING = 0x00000103
- STATUS_CANCELLED = 0xC0000120
- )
mp := getg().m
// A wait completion packet can only be associated with one timer at a time,
// so we need to cancel the previous one if it exists. This wouldn't be necessary
// another thread, so defer the cancellation until it is really necessary.
errno := stdcall(_NtCancelWaitCompletionPacket, mp.waitIocpHandle, 1)
switch errno {
- case STATUS_CANCELLED:
+ case windows.STATUS_CANCELLED:
// STATUS_CANCELLED is returned when the associated timer has already expired,
// in which automatically cancels the wait completion packet.
fallthrough
- case STATUS_SUCCESS:
+ case windows.STATUS_SUCCESS:
dt := -delay / 100 // relative sleep (negative), 100ns units
if stdcall(_SetWaitableTimer, mp.waitIocpTimer, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0) == 0 {
println("runtime: SetWaitableTimer failed; errno=", getlasterror())
println("runtime: NtAssociateWaitCompletionPacket failed; errno=", errno)
throw("runtime: netpoll failed")
}
- case STATUS_PENDING:
+ case windows.STATUS_PENDING:
// STATUS_PENDING is returned if the wait operation can't be canceled yet.
// This can happen if this thread was woken up by another event, such as a netpollBreak,
// and the timer expired just while calling NtCancelWaitCompletionPacket, in which case
func getCPUCount() int32 {
var mask, sysmask uintptr
- ret := stdcall(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
+ ret := stdcall(_GetProcessAffinityMask, windows.CurrentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
if ret != 0 {
n := 0
maskbits := int(unsafe.Sizeof(mask) * 8)
}
}
// use GetSystemInfo if GetProcessAffinityMask fails
- var info systeminfo
+ var info windows.SystemInfo
stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
- return int32(info.dwnumberofprocessors)
+ return int32(info.NumberOfProcessors)
}
func getPageSize() uintptr {
- var info systeminfo
+ var info windows.SystemInfo
stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
- return uintptr(info.dwpagesize)
+ return uintptr(info.PageSize)
}
-const (
- currentProcess = ^uintptr(0) // -1 = current process
- currentThread = ^uintptr(1) // -2 = current thread
-)
-
// in sys_windows_386.s and sys_windows_amd64.s:
func getlasterror() uint32
// resolution timer. createHighResTimer returns new timer
// handle or 0, if CreateWaitableTimerEx failed.
func createHighResTimer() uintptr {
- const (
- // As per @jstarks, see
- // https://github.com/golang/go/issues/8687#issuecomment-656259353
- _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002
-
- _SYNCHRONIZE = 0x00100000
- _TIMER_QUERY_STATE = 0x0001
- _TIMER_MODIFY_STATE = 0x0002
- )
+ // As per @jstarks, see
+ // https://github.com/golang/go/issues/8687#issuecomment-656259353
return stdcall(_CreateWaitableTimerExW, 0, 0,
- _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
- _SYNCHRONIZE|_TIMER_QUERY_STATE|_TIMER_MODIFY_STATE)
+ windows.CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
+ windows.SYNCHRONIZE|windows.TIMER_QUERY_STATE|windows.TIMER_MODIFY_STATE)
}
func initHighResTimer() {
)
// Check that we're ≥ 10.0.15063.
- info := _OSVERSIONINFOW{}
- info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
+ info := windows.OSVERSIONINFOW{}
+ info.OSVersionInfoSize = uint32(unsafe.Sizeof(info))
stdcall(_RtlGetVersion, uintptr(unsafe.Pointer(&info)))
- if info.majorVersion < 10 || (info.majorVersion == 10 && info.minorVersion == 0 && info.buildNumber < 15063) {
+ if info.MajorVersion < 10 || (info.MajorVersion == 10 && info.MinorVersion == 0 && info.BuildNumber < 15063) {
return
}
// of dedicated threads -- GUI, IO, computational, etc. Go processes use
// equivalent threads that all do a mix of GUI, IO, computations, etc.
// In such context dynamic priority boosting does nothing but harm, so we turn it off.
- stdcall(_SetProcessPriorityBoost, currentProcess, 1)
+ stdcall(_SetProcessPriorityBoost, windows.CurrentProcess, 1)
}
//go:nosplit
var result uintptr
if ns < 0 {
- result = stdcall(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
+ result = stdcall(_WaitForSingleObject, getg().m.waitsema, uintptr(windows.INFINITE))
} else {
start := nanotime()
elapsed := int64(0)
// Called on the new thread, cannot allocate Go memory.
func minit() {
var thandle uintptr
- if stdcall(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
+ if stdcall(_DuplicateHandle, windows.CurrentProcess, windows.CurrentThread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
print("runtime.minit: duplicatehandle failed; errno=", getlasterror(), "\n")
throw("runtime.minit: duplicatehandle failed")
}
// Query the true stack base from the OS. Currently we're
// running on a small assumed stack.
- var mbi memoryBasicInformation
+ var mbi windows.MemoryBasicInformation
res := stdcall(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
if res == 0 {
print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
// calling C functions that don't have stack checks and for
// lastcontinuehandler. We shouldn't be anywhere near this
// bound anyway.
- base := mbi.allocationBase + 16<<10
+ base := mbi.AllocationBase + 16<<10
// Sanity check the stack bounds.
g0 := getg()
if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
//go:nosplit
func usleep_no_g(us uint32) {
timeout := uintptr(us) / 1000 // ms units
- stdcall_no_g(_WaitForSingleObject, _INVALID_HANDLE_VALUE, timeout)
+ stdcall_no_g(_WaitForSingleObject, windows.INVALID_HANDLE_VALUE, timeout)
}
//go:nosplit
h = getg().m.highResTimer
dt := -10 * int64(us) // relative sleep (negative), 100ns units
stdcall(_SetWaitableTimer, h, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0)
- timeout = _INFINITE
+ timeout = windows.INFINITE
} else {
- h = _INVALID_HANDLE_VALUE
+ h = windows.INVALID_HANDLE_VALUE
timeout = uintptr(us) / 1000 // ms units
}
stdcall(_WaitForSingleObject, h, timeout)
var s uint32
switch _type {
- case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
- s = _SIGINT
- case _CTRL_CLOSE_EVENT, _CTRL_LOGOFF_EVENT, _CTRL_SHUTDOWN_EVENT:
- s = _SIGTERM
+ case windows.CTRL_C_EVENT, windows.CTRL_BREAK_EVENT:
+ s = windows.SIGINT
+ case windows.CTRL_CLOSE_EVENT, windows.CTRL_LOGOFF_EVENT, windows.CTRL_SHUTDOWN_EVENT:
+ s = windows.SIGTERM
default:
return 0
}
if sigsend(s) {
- if s == _SIGTERM {
+ if s == windows.SIGTERM {
// Windows terminates the process after this handler returns.
// Block indefinitely to give signal handlers a chance to clean up,
// but make sure to be properly parked first, so the rest of the
func profilem(mp *m, thread uintptr) {
// Align Context to 16 bytes.
- var c *context
+ var c *windows.Context
var cbuf [unsafe.Sizeof(*c) + 15]byte
- c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
+ c = (*windows.Context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
- c.contextflags = _CONTEXT_CONTROL
+ c.ContextFlags = windows.CONTEXT_CONTROL
stdcall(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
- gp := gFromSP(mp, c.sp())
+ gp := gFromSP(mp, c.SP())
- sigprof(c.ip(), c.sp(), c.lr(), gp, mp)
+ sigprof(c.PC(), c.SP(), c.LR(), gp, mp)
}
func gFromSP(mp *m, sp uintptr) *g {
}
func profileLoop() {
- stdcall(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
+ stdcall(_SetThreadPriority, windows.CurrentThread, windows.THREAD_PRIORITY_HIGHEST)
for {
- stdcall(_WaitForSingleObject, profiletimer, _INFINITE)
+ stdcall(_WaitForSingleObject, profiletimer, windows.INFINITE)
first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
for mp := first; mp != nil; mp = mp.alllink {
if mp == getg().m {
}
// Acquire our own handle to the thread.
var thread uintptr
- if stdcall(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
+ if stdcall(_DuplicateHandle, windows.CurrentProcess, mp.thread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
print("runtime: duplicatehandle failed; errno=", getlasterror(), "\n")
throw("duplicatehandle failed")
}
return
}
var thread uintptr
- if stdcall(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
+ if stdcall(_DuplicateHandle, windows.CurrentProcess, mp.thread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
print("runtime.preemptM: duplicatehandle failed; errno=", getlasterror(), "\n")
throw("runtime.preemptM: duplicatehandle failed")
}
unlock(&mp.threadLock)
// Prepare thread context buffer. This must be aligned to 16 bytes.
- var c *context
+ var c *windows.Context
var cbuf [unsafe.Sizeof(*c) + 15]byte
- c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
- c.contextflags = _CONTEXT_CONTROL
+ c = (*windows.Context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
+ c.ContextFlags = windows.CONTEXT_CONTROL
// Serialize thread suspension. SuspendThread is asynchronous,
// so it's otherwise possible for two threads to suspend each
unlock(&suspendLock)
// Does it want a preemption and is it safe to preempt?
- gp := gFromSP(mp, c.sp())
+ gp := gFromSP(mp, c.SP())
if gp != nil && wantAsyncPreempt(gp) {
- if ok, resumePC := isAsyncSafePoint(gp, c.ip(), c.sp(), c.lr()); ok {
+ if ok, resumePC := isAsyncSafePoint(gp, c.PC(), c.SP(), c.LR()); ok {
// Inject call to asyncPreempt
targetPC := abi.FuncPCABI0(asyncPreempt)
- c.pushCall(targetPC, resumePC)
+ c.PushCall(targetPC, resumePC)
stdcall(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
}
}
stdcall(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
return counter
}
+
+func stackcheck() {
+ // TODO: not implemented
+}
import (
"internal/abi"
+ "internal/runtime/sys"
"internal/syscall/windows"
"runtime"
"slices"
{"func in prologue", sehf1pc + 1, true},
{"anonymous func with frame", abi.FuncPCABIInternal(fnwithframe), true},
{"anonymous func without frame", abi.FuncPCABIInternal(fnwithoutframe), false},
- {"pc at func body", runtime.NewContextStub().GetPC(), true},
+ {"pc at func body", sys.GetCallerPC(), true},
}
for _, tt := range tests {
var base uintptr
// We don't need a real context,
// RtlVirtualUnwind just needs a context with
// valid a pc, sp and fp (aka bp).
- ctx := runtime.NewContextStub()
+ var ctx windows.Context
+ ctx.SetPC(sys.GetCallerPC())
+ ctx.SetSP(sys.GetCallerSP())
+ ctx.SetFP(runtime.GetCallerFp())
pcs := make([]uintptr, 15)
var base, frame uintptr
var n int
for i := 0; i < len(pcs); i++ {
- fn := windows.RtlLookupFunctionEntry(ctx.GetPC(), &base, nil)
+ fn := windows.RtlLookupFunctionEntry(ctx.PC(), &base, nil)
if fn == nil {
break
}
- pcs[i] = ctx.GetPC()
+ pcs[i] = ctx.PC()
n++
- windows.RtlVirtualUnwind(0, base, ctx.GetPC(), fn, unsafe.Pointer(ctx), nil, &frame, nil)
+ windows.RtlVirtualUnwind(0, base, ctx.PC(), fn, unsafe.Pointer(&ctx), nil, &frame, nil)
}
return pcs[:n]
}
t.Skip("skipping amd64-only test")
}
pcs := sehf3(false)
- testSehCallersEqual(t, pcs, []string{"runtime_test.sehCallers", "runtime_test.sehf4",
- "runtime_test.sehf3", "runtime_test.TestSehUnwind"})
+ testSehCallersEqual(t, pcs, []string{"runtime_test.sehf4", "runtime_test.sehf3", "runtime_test.TestSehUnwind"})
}
func TestSehUnwindPanic(t *testing.T) {
if runtime.GOARCH != "amd64" {
t.Skip("skipping amd64-only test")
}
- want := []string{"runtime_test.sehCallers", "runtime_test.TestSehUnwindPanic.func1", "runtime.gopanic",
+ want := []string{"runtime_test.TestSehUnwindPanic.func1", "runtime.gopanic",
"runtime_test.sehf4", "runtime_test.sehf3", "runtime_test.TestSehUnwindPanic"}
defer func() {
if r := recover(); r == nil {
if runtime.GOARCH != "amd64" {
t.Skip("skipping amd64-only test")
}
- want := []string{"runtime_test.sehCallers", "runtime_test.TestSehUnwindDoublePanic.func1.1", "runtime.gopanic",
+ want := []string{"runtime_test.TestSehUnwindDoublePanic.func1.1", "runtime.gopanic",
"runtime_test.TestSehUnwindDoublePanic.func1", "runtime.gopanic", "runtime_test.TestSehUnwindDoublePanic"}
defer func() {
defer func() {
if runtime.GOARCH != "amd64" {
t.Skip("skipping amd64-only test")
}
- want := []string{"runtime_test.sehCallers", "runtime_test.TestSehUnwindNilPointerPanic.func1", "runtime.gopanic",
+ want := []string{"runtime_test.TestSehUnwindNilPointerPanic.func1", "runtime.gopanic",
"runtime.sigpanic", "runtime_test.TestSehUnwindNilPointerPanic"}
defer func() {
if r := recover(); r == nil {
import (
"internal/abi"
+ "internal/runtime/syscall/windows"
"unsafe"
)
-const (
- _SEM_FAILCRITICALERRORS = 0x0001
- _SEM_NOGPFAULTERRORBOX = 0x0002
- _SEM_NOOPENFILEERRORBOX = 0x8000
-
- _WER_FAULT_REPORTING_NO_UI = 0x0020
-)
-
func preventErrorDialogs() {
errormode := stdcall(_GetErrorMode)
- stdcall(_SetErrorMode, errormode|_SEM_FAILCRITICALERRORS|_SEM_NOGPFAULTERRORBOX|_SEM_NOOPENFILEERRORBOX)
+ stdcall(_SetErrorMode, errormode|windows.SEM_FAILCRITICALERRORS|windows.SEM_NOGPFAULTERRORBOX|windows.SEM_NOOPENFILEERRORBOX)
// Disable WER fault reporting UI.
// Do this even if WER is disabled as a whole,
// as WER might be enabled later with setTraceback("wer")
// and we still want the fault reporting UI to be disabled if this happens.
var werflags uintptr
- stdcall(_WerGetFlags, currentProcess, uintptr(unsafe.Pointer(&werflags)))
- stdcall(_WerSetFlags, werflags|_WER_FAULT_REPORTING_NO_UI)
+ stdcall(_WerGetFlags, windows.CurrentProcess, uintptr(unsafe.Pointer(&werflags)))
+ stdcall(_WerSetFlags, werflags|windows.WER_FAULT_REPORTING_NO_UI)
}
// enableWER re-enables Windows error reporting without fault reporting UI.
func enableWER() {
// re-enable Windows Error Reporting
errormode := stdcall(_GetErrorMode)
- if errormode&_SEM_NOGPFAULTERRORBOX != 0 {
- stdcall(_SetErrorMode, errormode^_SEM_NOGPFAULTERRORBOX)
+ if errormode&windows.SEM_NOGPFAULTERRORBOX != 0 {
+ stdcall(_SetErrorMode, errormode^windows.SEM_NOGPFAULTERRORBOX)
}
}
// by calling runtime.abort function.
//
//go:nosplit
-func isAbort(r *context) bool {
- pc := r.ip()
+func isAbort(r *windows.Context) bool {
+ pc := r.PC()
if GOARCH == "386" || GOARCH == "amd64" {
// In the case of an abort, the exception IP is one byte after
// the INT3 (this differs from UNIX OSes).
// because of a stack overflow.
//
//go:nosplit
-func isgoexception(info *exceptionrecord, r *context) bool {
+func isgoexception(info *windows.ExceptionRecord, r *windows.Context) bool {
// Only handle exception if executing instructions in Go binary
// (not Windows library code).
// TODO(mwhudson): needs to loop to support shared libs
- if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
+ if r.PC() < firstmoduledata.text || firstmoduledata.etext < r.PC() {
return false
}
// Go will only handle some exceptions.
- switch info.exceptioncode {
+ switch info.ExceptionCode {
default:
return false
- case _EXCEPTION_ACCESS_VIOLATION:
- case _EXCEPTION_IN_PAGE_ERROR:
- case _EXCEPTION_INT_DIVIDE_BY_ZERO:
- case _EXCEPTION_INT_OVERFLOW:
- case _EXCEPTION_FLT_DENORMAL_OPERAND:
- case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
- case _EXCEPTION_FLT_INEXACT_RESULT:
- case _EXCEPTION_FLT_OVERFLOW:
- case _EXCEPTION_FLT_UNDERFLOW:
- case _EXCEPTION_BREAKPOINT:
- case _EXCEPTION_ILLEGAL_INSTRUCTION: // breakpoint arrives this way on arm64
+ case windows.EXCEPTION_ACCESS_VIOLATION:
+ case windows.EXCEPTION_IN_PAGE_ERROR:
+ case windows.EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case windows.EXCEPTION_INT_OVERFLOW:
+ case windows.EXCEPTION_FLT_DENORMAL_OPERAND:
+ case windows.EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case windows.EXCEPTION_FLT_INEXACT_RESULT:
+ case windows.EXCEPTION_FLT_OVERFLOW:
+ case windows.EXCEPTION_FLT_UNDERFLOW:
+ case windows.EXCEPTION_BREAKPOINT:
+ case windows.EXCEPTION_ILLEGAL_INSTRUCTION: // breakpoint arrives this way on arm64
}
return true
}
// It is nosplit for the same reason as exceptionhandler.
//
//go:nosplit
-func sigtrampgo(ep *exceptionpointers, kind int) int32 {
+func sigtrampgo(ep *windows.ExceptionPointers, kind int) int32 {
gp := sigFetchG()
if gp == nil {
- return _EXCEPTION_CONTINUE_SEARCH
+ return windows.EXCEPTION_CONTINUE_SEARCH
}
- var fn func(info *exceptionrecord, r *context, gp *g) int32
+ var fn func(info *windows.ExceptionRecord, r *windows.Context, gp *g) int32
switch kind {
case callbackVEH:
fn = exceptionhandler
var ret int32
if gp != gp.m.g0 {
systemstack(func() {
- ret = fn(ep.record, ep.context, gp)
+ ret = fn(ep.Record, ep.Context, gp)
})
} else {
- ret = fn(ep.record, ep.context, gp)
+ ret = fn(ep.Record, ep.Context, gp)
}
- if ret == _EXCEPTION_CONTINUE_SEARCH {
+ if ret == windows.EXCEPTION_CONTINUE_SEARCH {
return ret
}
// will not actually return to the original frame, so the registers
// are effectively dead. But this does mean we can't use the
// same mechanism for async preemption.
- if ep.context.ip() == abi.FuncPCABI0(sigresume) {
+ if ep.Context.PC() == abi.FuncPCABI0(sigresume) {
// sigresume has already been set up by a previous exception.
return ret
}
- prepareContextForSigResume(ep.context)
- ep.context.set_sp(gp.m.g0.sched.sp)
- ep.context.set_ip(abi.FuncPCABI0(sigresume))
+ prepareContextForSigResume(ep.Context)
+ ep.Context.SetSP(gp.m.g0.sched.sp)
+ ep.Context.SetPC(abi.FuncPCABI0(sigresume))
return ret
}
// _EXCEPTION_BREAKPOINT, which is raised by abort() if we overflow the g0 stack.
//
//go:nosplit
-func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
+func exceptionhandler(info *windows.ExceptionRecord, r *windows.Context, gp *g) int32 {
if !isgoexception(info, r) {
- return _EXCEPTION_CONTINUE_SEARCH
+ return windows.EXCEPTION_CONTINUE_SEARCH
}
if gp.throwsplit || isAbort(r) {
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
- gp.sig = info.exceptioncode
- gp.sigcode0 = info.exceptioninformation[0]
- gp.sigcode1 = info.exceptioninformation[1]
- gp.sigpc = r.ip()
+ gp.sig = info.ExceptionCode
+ gp.sigcode0 = info.ExceptionInformation[0]
+ gp.sigcode1 = info.ExceptionInformation[1]
+ gp.sigpc = r.PC()
// Only push runtime·sigpanic if r.ip() != 0.
// If r.ip() == 0, probably panicked because of a
// The exception is not from asyncPreempt, so not to push a
// sigpanic call to make it look like that. Instead, just
// overwrite the PC. (See issue #35773)
- if r.ip() != 0 && r.ip() != abi.FuncPCABI0(asyncPreempt) {
- r.pushCall(abi.FuncPCABI0(sigpanic0), r.ip())
+ if r.PC() != 0 && r.PC() != abi.FuncPCABI0(asyncPreempt) {
+ r.PushCall(abi.FuncPCABI0(sigpanic0), r.PC())
} else {
// Not safe to push the call. Just clobber the frame.
- r.set_ip(abi.FuncPCABI0(sigpanic0))
+ r.SetPC(abi.FuncPCABI0(sigpanic0))
}
- return _EXCEPTION_CONTINUE_EXECUTION
+ return windows.EXCEPTION_CONTINUE_EXECUTION
}
// sehhandler is reached as part of the SEH chain.
// It is nosplit for the same reason as exceptionhandler.
//
//go:nosplit
-func sehhandler(_ *exceptionrecord, _ uint64, _ *context, dctxt *_DISPATCHER_CONTEXT) int32 {
+func sehhandler(_ *windows.ExceptionRecord, _ uint64, _ *windows.Context, dctxt *windows.DISPATCHER_CONTEXT) int32 {
g0 := getg()
if g0 == nil || g0.m.curg == nil {
// No g available, nothing to do here.
- return _EXCEPTION_CONTINUE_SEARCH_SEH
+ return windows.EXCEPTION_CONTINUE_SEARCH_SEH
}
// The Windows SEH machinery will unwind the stack until it finds
// a frame with a handler for the exception or until the frame is
// To work around this, manually unwind the stack until the top of the goroutine
// stack is reached, and then pass the control back to Windows.
gp := g0.m.curg
- ctxt := dctxt.ctx()
+ ctxt := dctxt.Ctx()
var base, sp uintptr
for {
- entry := stdcall(_RtlLookupFunctionEntry, ctxt.ip(), uintptr(unsafe.Pointer(&base)), 0)
+ entry := stdcall(_RtlLookupFunctionEntry, ctxt.PC(), uintptr(unsafe.Pointer(&base)), 0)
if entry == 0 {
break
}
- stdcall(_RtlVirtualUnwind, 0, base, ctxt.ip(), entry, uintptr(unsafe.Pointer(ctxt)), 0, uintptr(unsafe.Pointer(&sp)), 0)
+ stdcall(_RtlVirtualUnwind, 0, base, ctxt.PC(), entry, uintptr(unsafe.Pointer(ctxt)), 0, uintptr(unsafe.Pointer(&sp)), 0)
if sp < gp.stack.lo || gp.stack.hi <= sp {
break
}
}
- return _EXCEPTION_CONTINUE_SEARCH_SEH
+ return windows.EXCEPTION_CONTINUE_SEARCH_SEH
}
// It seems Windows searches ContinueHandler's list even
// It is nosplit for the same reason as exceptionhandler.
//
//go:nosplit
-func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
+func firstcontinuehandler(info *windows.ExceptionRecord, r *windows.Context, gp *g) int32 {
if !isgoexception(info, r) {
- return _EXCEPTION_CONTINUE_SEARCH
+ return windows.EXCEPTION_CONTINUE_SEARCH
}
- return _EXCEPTION_CONTINUE_EXECUTION
+ return windows.EXCEPTION_CONTINUE_EXECUTION
}
// lastcontinuehandler is reached, because runtime cannot handle
// It is nosplit for the same reason as exceptionhandler.
//
//go:nosplit
-func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
+func lastcontinuehandler(info *windows.ExceptionRecord, r *windows.Context, gp *g) int32 {
if islibrary || isarchive {
// Go DLL/archive has been loaded in a non-go program.
// If the exception does not originate from go, the go runtime
// should not take responsibility of crashing the process.
- return _EXCEPTION_CONTINUE_SEARCH
+ return windows.EXCEPTION_CONTINUE_SEARCH
}
// VEH is called before SEH, but arm64 MSVC DLLs use SEH to trap
// arm64 and it's an illegal instruction and this is coming from
// non-Go code, then assume it's this runtime probing happen, and
// pass that onward to SEH.
- if GOARCH == "arm64" && info.exceptioncode == _EXCEPTION_ILLEGAL_INSTRUCTION &&
- (r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip()) {
- return _EXCEPTION_CONTINUE_SEARCH
+ if GOARCH == "arm64" && info.ExceptionCode == windows.EXCEPTION_ILLEGAL_INSTRUCTION &&
+ (r.PC() < firstmoduledata.text || firstmoduledata.etext < r.PC()) {
+ return windows.EXCEPTION_CONTINUE_SEARCH
}
winthrow(info, r, gp)
// Always called on g0. gp is the G where the exception occurred.
//
//go:nosplit
-func winthrow(info *exceptionrecord, r *context, gp *g) {
+func winthrow(info *windows.ExceptionRecord, r *windows.Context, gp *g) {
g0 := getg()
if panicking.Load() != 0 { // traceback already printed
g0.stackguard0 = g0.stack.lo + stackGuard
g0.stackguard1 = g0.stackguard0
- print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
+ print("Exception ", hex(info.ExceptionCode), " ", hex(info.ExceptionInformation[0]), " ", hex(info.ExceptionInformation[1]), " ", hex(r.PC()), "\n")
- print("PC=", hex(r.ip()), "\n")
+ print("PC=", hex(r.PC()), "\n")
if g0.m.incgo && gp == g0.m.g0 && g0.m.curg != nil {
if iscgo {
print("signal arrived during external code execution\n")
level, _, docrash := gotraceback()
if level > 0 {
- tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
+ tracebacktrap(r.PC(), r.SP(), r.LR(), gp)
tracebackothers(gp)
dumpregs(r)
}
}
switch gp.sig {
- case _EXCEPTION_ACCESS_VIOLATION, _EXCEPTION_IN_PAGE_ERROR:
+ case windows.EXCEPTION_ACCESS_VIOLATION, windows.EXCEPTION_IN_PAGE_ERROR:
if gp.sigcode1 < 0x1000 {
panicmem()
}
print("unexpected fault address ", hex(gp.sigcode1), "\n")
}
throw("fault")
- case _EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case windows.EXCEPTION_INT_DIVIDE_BY_ZERO:
panicdivide()
- case _EXCEPTION_INT_OVERFLOW:
+ case windows.EXCEPTION_INT_OVERFLOW:
panicoverflow()
- case _EXCEPTION_FLT_DENORMAL_OPERAND,
- _EXCEPTION_FLT_DIVIDE_BY_ZERO,
- _EXCEPTION_FLT_INEXACT_RESULT,
- _EXCEPTION_FLT_OVERFLOW,
- _EXCEPTION_FLT_UNDERFLOW:
+ case windows.EXCEPTION_FLT_DENORMAL_OPERAND,
+ windows.EXCEPTION_FLT_DIVIDE_BY_ZERO,
+ windows.EXCEPTION_FLT_INEXACT_RESULT,
+ windows.EXCEPTION_FLT_OVERFLOW,
+ windows.EXCEPTION_FLT_UNDERFLOW:
panicfloat()
}
throw("fault")
// This provides the expected exit status for the shell.
//
//go:nosplit
-func dieFromException(info *exceptionrecord, r *context) {
+func dieFromException(info *windows.ExceptionRecord, r *windows.Context) {
if info == nil {
gp := getg()
if gp.sig != 0 {
// Try to reconstruct an exception record from
// the exception information stored in gp.
- info = &exceptionrecord{
- exceptionaddress: gp.sigpc,
- exceptioncode: gp.sig,
- numberparameters: 2,
+ info = &windows.ExceptionRecord{
+ ExceptionAddress: gp.sigpc,
+ ExceptionCode: gp.sig,
+ NumberParameters: 2,
}
- info.exceptioninformation[0] = gp.sigcode0
- info.exceptioninformation[1] = gp.sigcode1
+ info.ExceptionInformation[0] = gp.sigcode0
+ info.ExceptionInformation[1] = gp.sigcode1
} else {
// By default, a failing Go application exits with exit code 2.
// Use this value when gp does not contain exception info.
- info = &exceptionrecord{
- exceptioncode: 2,
+ info = &windows.ExceptionRecord{
+ ExceptionCode: 2,
}
}
}
- const FAIL_FAST_GENERATE_EXCEPTION_ADDRESS = 0x1
- stdcall(_RaiseFailFastException, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(r)), FAIL_FAST_GENERATE_EXCEPTION_ADDRESS)
+ stdcall(_RaiseFailFastException, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(r)), windows.FAIL_FAST_GENERATE_EXCEPTION_ADDRESS)
}
// gsignalStack is unused on Windows.
--- /dev/null
+// Copyright 2025 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.
+
+package runtime
+
+import "internal/runtime/syscall/windows"
+
+func prepareContextForSigResume(c *windows.Context) {
+ c.Edx = c.Esp
+ c.Ecx = c.Eip
+}
+
+func dumpregs(r *windows.Context) {
+ print("eax ", hex(r.Eax), "\n")
+ print("ebx ", hex(r.Ebx), "\n")
+ print("ecx ", hex(r.Ecx), "\n")
+ print("edx ", hex(r.Edx), "\n")
+ print("edi ", hex(r.Edi), "\n")
+ print("esi ", hex(r.Esi), "\n")
+ print("ebp ", hex(r.Ebp), "\n")
+ print("esp ", hex(r.Esp), "\n")
+ print("eip ", hex(r.Eip), "\n")
+ print("eflags ", hex(r.EFlags), "\n")
+ print("cs ", hex(r.SegCs), "\n")
+ print("fs ", hex(r.SegFs), "\n")
+ print("gs ", hex(r.SegGs), "\n")
+}
--- /dev/null
+// Copyright 2025 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.
+
+package runtime
+
+import "internal/runtime/syscall/windows"
+
+func prepareContextForSigResume(c *windows.Context) {
+ c.R8 = c.Rsp
+ c.R9 = c.Rip
+}
+
+func dumpregs(r *windows.Context) {
+ print("rax ", hex(r.Rax), "\n")
+ print("rbx ", hex(r.Rbx), "\n")
+ print("rcx ", hex(r.Rcx), "\n")
+ print("rdx ", hex(r.Rdx), "\n")
+ print("rdi ", hex(r.Rdi), "\n")
+ print("rsi ", hex(r.Rsi), "\n")
+ print("rbp ", hex(r.Rbp), "\n")
+ print("rsp ", hex(r.Rsp), "\n")
+ print("r8 ", hex(r.R8), "\n")
+ print("r9 ", hex(r.R9), "\n")
+ print("r10 ", hex(r.R10), "\n")
+ print("r11 ", hex(r.R11), "\n")
+ print("r12 ", hex(r.R12), "\n")
+ print("r13 ", hex(r.R13), "\n")
+ print("r14 ", hex(r.R14), "\n")
+ print("r15 ", hex(r.R15), "\n")
+ print("rip ", hex(r.Rip), "\n")
+ print("rflags ", hex(r.EFlags), "\n")
+ print("cs ", hex(r.SegCs), "\n")
+ print("fs ", hex(r.SegFs), "\n")
+ print("gs ", hex(r.SegGs), "\n")
+}
--- /dev/null
+// Copyright 2025 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.
+
+package runtime
+
+import "internal/runtime/syscall/windows"
+
+func prepareContextForSigResume(c *windows.Context) {
+ c.X[0] = c.XSp
+ c.X[1] = c.Pc
+}
+
+func dumpregs(r *windows.Context) {
+ print("r0 ", hex(r.X[0]), "\n")
+ print("r1 ", hex(r.X[1]), "\n")
+ print("r2 ", hex(r.X[2]), "\n")
+ print("r3 ", hex(r.X[3]), "\n")
+ print("r4 ", hex(r.X[4]), "\n")
+ print("r5 ", hex(r.X[5]), "\n")
+ print("r6 ", hex(r.X[6]), "\n")
+ print("r7 ", hex(r.X[7]), "\n")
+ print("r8 ", hex(r.X[8]), "\n")
+ print("r9 ", hex(r.X[9]), "\n")
+ print("r10 ", hex(r.X[10]), "\n")
+ print("r11 ", hex(r.X[11]), "\n")
+ print("r12 ", hex(r.X[12]), "\n")
+ print("r13 ", hex(r.X[13]), "\n")
+ print("r14 ", hex(r.X[14]), "\n")
+ print("r15 ", hex(r.X[15]), "\n")
+ print("r16 ", hex(r.X[16]), "\n")
+ print("r17 ", hex(r.X[17]), "\n")
+ print("r18 ", hex(r.X[18]), "\n")
+ print("r19 ", hex(r.X[19]), "\n")
+ print("r20 ", hex(r.X[20]), "\n")
+ print("r21 ", hex(r.X[21]), "\n")
+ print("r22 ", hex(r.X[22]), "\n")
+ print("r23 ", hex(r.X[23]), "\n")
+ print("r24 ", hex(r.X[24]), "\n")
+ print("r25 ", hex(r.X[25]), "\n")
+ print("r26 ", hex(r.X[26]), "\n")
+ print("r27 ", hex(r.X[27]), "\n")
+ print("r28 ", hex(r.X[28]), "\n")
+ print("r29 ", hex(r.X[29]), "\n")
+ print("lr ", hex(r.X[30]), "\n")
+ print("sp ", hex(r.XSp), "\n")
+ print("pc ", hex(r.Pc), "\n")
+ print("cpsr ", hex(r.Cpsr), "\n")
+}