diff --git a/src/internal/runtime/syscall/windows/defs_windows.go b/src/internal/runtime/syscall/windows/defs_windows.go new file mode 100644 index 00000000000..6b1098098c9 --- /dev/null +++ b/src/internal/runtime/syscall/windows/defs_windows.go @@ -0,0 +1,159 @@ +// 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 +} diff --git a/src/internal/runtime/syscall/windows/defs_windows_386.go b/src/internal/runtime/syscall/windows/defs_windows_386.go new file mode 100644 index 00000000000..6c2271efb0f --- /dev/null +++ b/src/internal/runtime/syscall/windows/defs_windows_386.go @@ -0,0 +1,79 @@ +// 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 +} diff --git a/src/internal/runtime/syscall/windows/defs_windows_amd64.go b/src/internal/runtime/syscall/windows/defs_windows_amd64.go new file mode 100644 index 00000000000..018124488b7 --- /dev/null +++ b/src/internal/runtime/syscall/windows/defs_windows_amd64.go @@ -0,0 +1,99 @@ +// 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 +} diff --git a/src/internal/runtime/syscall/windows/defs_windows_arm64.go b/src/internal/runtime/syscall/windows/defs_windows_arm64.go new file mode 100644 index 00000000000..c05573a5311 --- /dev/null +++ b/src/internal/runtime/syscall/windows/defs_windows_arm64.go @@ -0,0 +1,75 @@ +// 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 +} diff --git a/src/internal/syscall/windows/memory_windows.go b/src/internal/syscall/windows/memory_windows.go deleted file mode 100644 index 8fb34cf3492..00000000000 --- a/src/internal/syscall/windows/memory_windows.go +++ /dev/null @@ -1,24 +0,0 @@ -// 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 -} diff --git a/src/internal/syscall/windows/types_windows.go b/src/internal/syscall/windows/types_windows.go index 33767391434..fe9e41f2f86 100644 --- a/src/internal/syscall/windows/types_windows.go +++ b/src/internal/syscall/windows/types_windows.go @@ -5,6 +5,7 @@ package windows import ( + "internal/runtime/syscall/windows" "syscall" "unsafe" ) @@ -276,3 +277,7 @@ type FILE_COMPLETION_INFORMATION struct { // 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 diff --git a/src/runtime/defs_windows.go b/src/runtime/defs_windows.go deleted file mode 100644 index 2f09afbe1fe..00000000000 --- a/src/runtime/defs_windows.go +++ /dev/null @@ -1,101 +0,0 @@ -// 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 -} diff --git a/src/runtime/defs_windows_386.go b/src/runtime/defs_windows_386.go deleted file mode 100644 index 12cd442eb56..00000000000 --- a/src/runtime/defs_windows_386.go +++ /dev/null @@ -1,100 +0,0 @@ -// 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 -} diff --git a/src/runtime/defs_windows_amd64.go b/src/runtime/defs_windows_amd64.go deleted file mode 100644 index 9bb7ee80adf..00000000000 --- a/src/runtime/defs_windows_amd64.go +++ /dev/null @@ -1,128 +0,0 @@ -// 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 -} diff --git a/src/runtime/defs_windows_arm64.go b/src/runtime/defs_windows_arm64.go deleted file mode 100644 index 077bed24e2a..00000000000 --- a/src/runtime/defs_windows_arm64.go +++ /dev/null @@ -1,121 +0,0 @@ -// 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 -} diff --git a/src/runtime/export_windows_test.go b/src/runtime/export_windows_test.go index caaf2dae51c..f44e24bbacf 100644 --- a/src/runtime/export_windows_test.go +++ b/src/runtime/export_windows_test.go @@ -7,7 +7,7 @@ package runtime import ( - "internal/runtime/sys" + "internal/runtime/syscall/windows" "unsafe" ) @@ -17,23 +17,11 @@ var ( ) 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() } diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go index 93137e47097..db5d043506a 100644 --- a/src/runtime/netpoll_windows.go +++ b/src/runtime/netpoll_windows.go @@ -7,13 +7,10 @@ package runtime 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 @@ -59,7 +56,7 @@ func unpackNetpollSource(key uintptr) uint8 { // Keep these in sync. type pollOperation struct { // used by windows - _ overlapped + _ windows.Overlapped // used by netpoll pd *pollDesc mode int32 @@ -90,19 +87,19 @@ func pollOperationFromOverlappedEntry(e *overlappedEntry) *pollOperation { // 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") @@ -152,7 +149,7 @@ func netpollBreak() { // 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 } @@ -182,7 +179,7 @@ func netpoll(delay int64) (gList, int32) { } } if delay < 0 { - wait = _INFINITE + wait = windows.INFINITE } else if delay == 0 { wait = 0 } else if delay < 1e6 { @@ -200,7 +197,7 @@ func netpoll(delay int64) (gList, int32) { 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, ")") @@ -243,11 +240,6 @@ func netpoll(delay int64) (gList, int32) { // 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 @@ -258,11 +250,11 @@ func netpollQueueTimer(delay int64) (signaled bool) { // 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()) @@ -273,7 +265,7 @@ func netpollQueueTimer(delay int64) (signaled bool) { 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 diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index ab4e165baec..f47419cf7df 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -323,7 +323,7 @@ func monitorSuspendResume() { 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) @@ -337,22 +337,17 @@ func getCPUCount() int32 { } } // 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 @@ -405,18 +400,11 @@ var haveHighResSleep = false // 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() { @@ -454,10 +442,10 @@ func initLongPathSupport() { ) // 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 } @@ -493,7 +481,7 @@ func osinit() { // 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 @@ -671,7 +659,7 @@ func semasleep(ns int64) int32 { 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) @@ -828,7 +816,7 @@ func sigblock(exiting bool) { // 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") } @@ -863,7 +851,7 @@ func minit() { // 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") @@ -875,7 +863,7 @@ func minit() { // 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 { @@ -1000,7 +988,7 @@ func osyield() { //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 @@ -1013,9 +1001,9 @@ func usleep(us uint32) { 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) @@ -1026,16 +1014,16 @@ func ctrlHandler(_type uint32) uintptr { 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 @@ -1054,16 +1042,16 @@ var profiletimer uintptr 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 { @@ -1080,10 +1068,10 @@ 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 { @@ -1101,7 +1089,7 @@ func profileLoop() { } // 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") } @@ -1183,17 +1171,17 @@ func preemptM(mp *m) { 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 @@ -1227,12 +1215,12 @@ func preemptM(mp *m) { 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))) } } diff --git a/src/runtime/os_windows_arm64.go b/src/runtime/os_windows_arm64.go index bd80c08b0e3..62caea7c2c6 100644 --- a/src/runtime/os_windows_arm64.go +++ b/src/runtime/os_windows_arm64.go @@ -12,3 +12,7 @@ func cputicks() int64 { stdcall(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter))) return counter } + +func stackcheck() { + // TODO: not implemented +} diff --git a/src/runtime/runtime-seh_windows_test.go b/src/runtime/runtime-seh_windows_test.go index ca92d7f178f..8503a0550c4 100644 --- a/src/runtime/runtime-seh_windows_test.go +++ b/src/runtime/runtime-seh_windows_test.go @@ -6,6 +6,7 @@ package runtime_test import ( "internal/abi" + "internal/runtime/sys" "internal/syscall/windows" "runtime" "slices" @@ -47,7 +48,7 @@ func TestSehLookupFunctionEntry(t *testing.T) { {"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 @@ -68,19 +69,22 @@ func sehCallers() []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] } @@ -129,15 +133,14 @@ func TestSehUnwind(t *testing.T) { 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 { @@ -153,7 +156,7 @@ func TestSehUnwindDoublePanic(t *testing.T) { 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() { @@ -175,7 +178,7 @@ func TestSehUnwindNilPointerPanic(t *testing.T) { 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 { diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go index f7628a0165b..40547b8113f 100644 --- a/src/runtime/signal_windows.go +++ b/src/runtime/signal_windows.go @@ -6,36 +6,29 @@ package runtime 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) } } @@ -62,8 +55,8 @@ func initExceptionHandler() { // 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). @@ -79,29 +72,29 @@ func isAbort(r *context) bool { // 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 } @@ -134,13 +127,13 @@ func sigFetchG() *g { // 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 @@ -169,12 +162,12 @@ func sigtrampgo(ep *exceptionpointers, kind int) int32 { 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 } @@ -189,13 +182,13 @@ func sigtrampgo(ep *exceptionpointers, kind int) int32 { // 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 } @@ -207,9 +200,9 @@ func sigtrampgo(ep *exceptionpointers, kind int) int32 { // _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) { @@ -226,10 +219,10 @@ func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { // 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 @@ -244,13 +237,13 @@ func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { // 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. @@ -258,11 +251,11 @@ func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { // 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 @@ -275,19 +268,19 @@ func sehhandler(_ *exceptionrecord, _ uint64, _ *context, dctxt *_DISPATCHER_CON // 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 @@ -298,11 +291,11 @@ func sehhandler(_ *exceptionrecord, _ uint64, _ *context, dctxt *_DISPATCHER_CON // 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 @@ -311,12 +304,12 @@ func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 { // 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 @@ -325,9 +318,9 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 { // 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) @@ -337,7 +330,7 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 { // 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 @@ -352,9 +345,9 @@ func winthrow(info *exceptionrecord, r *context, gp *g) { 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") @@ -368,7 +361,7 @@ func winthrow(info *exceptionrecord, r *context, gp *g) { 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) } @@ -387,7 +380,7 @@ func sigpanic() { } 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() } @@ -403,15 +396,15 @@ func sigpanic() { 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") @@ -444,29 +437,28 @@ func crash() { // 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. diff --git a/src/runtime/signal_windows_386.go b/src/runtime/signal_windows_386.go new file mode 100644 index 00000000000..1c731290b6b --- /dev/null +++ b/src/runtime/signal_windows_386.go @@ -0,0 +1,28 @@ +// 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") +} diff --git a/src/runtime/signal_windows_amd64.go b/src/runtime/signal_windows_amd64.go new file mode 100644 index 00000000000..ecb7024548d --- /dev/null +++ b/src/runtime/signal_windows_amd64.go @@ -0,0 +1,36 @@ +// 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") +} diff --git a/src/runtime/signal_windows_arm64.go b/src/runtime/signal_windows_arm64.go new file mode 100644 index 00000000000..78bddb9fb3c --- /dev/null +++ b/src/runtime/signal_windows_arm64.go @@ -0,0 +1,49 @@ +// 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") +}