mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: move Windows types and consts to internal/runtime/syscall/windows
This CL doesn't change any behavior, it just moves code around to reduce the size of the runtime package and remove some duplicated symbols. Updates #51087. Cq-Include-Trybots: luci.golang.try:gotip-windows-arm64 Change-Id: I3d3e5f214f045c24fb5d4050d56e7b0822a6e4b5 Reviewed-on: https://go-review.googlesource.com/c/go/+/698098 Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
cc8a6780ac
commit
889e71c2ac
19 changed files with 681 additions and 658 deletions
159
src/internal/runtime/syscall/windows/defs_windows.go
Normal file
159
src/internal/runtime/syscall/windows/defs_windows.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
79
src/internal/runtime/syscall/windows/defs_windows_386.go
Normal file
79
src/internal/runtime/syscall/windows/defs_windows_386.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
99
src/internal/runtime/syscall/windows/defs_windows_amd64.go
Normal file
99
src/internal/runtime/syscall/windows/defs_windows_amd64.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
75
src/internal/runtime/syscall/windows/defs_windows_arm64.go
Normal file
75
src/internal/runtime/syscall/windows/defs_windows_arm64.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/runtime/syscall/windows"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"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/win32/api/winnt/ns-winnt-osversioninfoexa
|
||||||
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
|
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
|
||||||
const VER_NT_WORKSTATION = 0x0000001
|
const VER_NT_WORKSTATION = 0x0000001
|
||||||
|
|
||||||
|
type MemoryBasicInformation = windows.MemoryBasicInformation
|
||||||
|
|
||||||
|
type Context = windows.Context
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"internal/runtime/sys"
|
"internal/runtime/syscall/windows"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -17,23 +17,11 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func NumberOfProcessors() int32 {
|
func NumberOfProcessors() int32 {
|
||||||
var info systeminfo
|
var info windows.SystemInfo
|
||||||
stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
|
stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
|
||||||
return int32(info.dwnumberofprocessors)
|
return int32(info.NumberOfProcessors)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContextStub struct {
|
func GetCallerFp() uintptr {
|
||||||
context
|
return getcallerfp()
|
||||||
}
|
|
||||||
|
|
||||||
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}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,10 @@ package runtime
|
||||||
import (
|
import (
|
||||||
"internal/goarch"
|
"internal/goarch"
|
||||||
"internal/runtime/atomic"
|
"internal/runtime/atomic"
|
||||||
|
"internal/runtime/syscall/windows"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const _DWORD_MAX = 0xffffffff
|
|
||||||
|
|
||||||
const _INVALID_HANDLE_VALUE = ^uintptr(0)
|
|
||||||
|
|
||||||
// Sources are used to identify the event that created an overlapped entry.
|
// 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
|
// 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
|
// 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.
|
// Keep these in sync.
|
||||||
type pollOperation struct {
|
type pollOperation struct {
|
||||||
// used by windows
|
// used by windows
|
||||||
_ overlapped
|
_ windows.Overlapped
|
||||||
// used by netpoll
|
// used by netpoll
|
||||||
pd *pollDesc
|
pd *pollDesc
|
||||||
mode int32
|
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
|
// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped_entry
|
||||||
type overlappedEntry struct {
|
type overlappedEntry struct {
|
||||||
key uintptr
|
key uintptr
|
||||||
ov *overlapped
|
ov *windows.Overlapped
|
||||||
internal uintptr
|
internal uintptr
|
||||||
qty uint32
|
qty uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
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
|
netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak
|
||||||
)
|
)
|
||||||
|
|
||||||
func netpollinit() {
|
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 {
|
if iocphandle == 0 {
|
||||||
println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")")
|
println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")")
|
||||||
throw("runtime: netpollinit failed")
|
throw("runtime: netpollinit failed")
|
||||||
|
|
@ -152,7 +149,7 @@ func netpollBreak() {
|
||||||
// delay == 0: does not block, just polls
|
// delay == 0: does not block, just polls
|
||||||
// delay > 0: block for up to that many nanoseconds
|
// delay > 0: block for up to that many nanoseconds
|
||||||
func netpoll(delay int64) (gList, int32) {
|
func netpoll(delay int64) (gList, int32) {
|
||||||
if iocphandle == _INVALID_HANDLE_VALUE {
|
if iocphandle == windows.INVALID_HANDLE_VALUE {
|
||||||
return gList{}, 0
|
return gList{}, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +179,7 @@ func netpoll(delay int64) (gList, int32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if delay < 0 {
|
if delay < 0 {
|
||||||
wait = _INFINITE
|
wait = windows.INFINITE
|
||||||
} else if delay == 0 {
|
} else if delay == 0 {
|
||||||
wait = 0
|
wait = 0
|
||||||
} else if delay < 1e6 {
|
} 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 {
|
if stdcall(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
|
||||||
mp.blocked = false
|
mp.blocked = false
|
||||||
errno := getlasterror()
|
errno := getlasterror()
|
||||||
if errno == _WAIT_TIMEOUT {
|
if errno == windows.WAIT_TIMEOUT {
|
||||||
return gList{}, 0
|
return gList{}, 0
|
||||||
}
|
}
|
||||||
println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
|
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.
|
// netpollQueueTimer queues a timer to wake up the poller after the given delay.
|
||||||
// It returns true if the timer expired during this call.
|
// It returns true if the timer expired during this call.
|
||||||
func netpollQueueTimer(delay int64) (signaled bool) {
|
func netpollQueueTimer(delay int64) (signaled bool) {
|
||||||
const (
|
|
||||||
STATUS_SUCCESS = 0x00000000
|
|
||||||
STATUS_PENDING = 0x00000103
|
|
||||||
STATUS_CANCELLED = 0xC0000120
|
|
||||||
)
|
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
// A wait completion packet can only be associated with one timer at a time,
|
// 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
|
// 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.
|
// another thread, so defer the cancellation until it is really necessary.
|
||||||
errno := stdcall(_NtCancelWaitCompletionPacket, mp.waitIocpHandle, 1)
|
errno := stdcall(_NtCancelWaitCompletionPacket, mp.waitIocpHandle, 1)
|
||||||
switch errno {
|
switch errno {
|
||||||
case STATUS_CANCELLED:
|
case windows.STATUS_CANCELLED:
|
||||||
// STATUS_CANCELLED is returned when the associated timer has already expired,
|
// STATUS_CANCELLED is returned when the associated timer has already expired,
|
||||||
// in which automatically cancels the wait completion packet.
|
// in which automatically cancels the wait completion packet.
|
||||||
fallthrough
|
fallthrough
|
||||||
case STATUS_SUCCESS:
|
case windows.STATUS_SUCCESS:
|
||||||
dt := -delay / 100 // relative sleep (negative), 100ns units
|
dt := -delay / 100 // relative sleep (negative), 100ns units
|
||||||
if stdcall(_SetWaitableTimer, mp.waitIocpTimer, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0) == 0 {
|
if stdcall(_SetWaitableTimer, mp.waitIocpTimer, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0) == 0 {
|
||||||
println("runtime: SetWaitableTimer failed; errno=", getlasterror())
|
println("runtime: SetWaitableTimer failed; errno=", getlasterror())
|
||||||
|
|
@ -273,7 +265,7 @@ func netpollQueueTimer(delay int64) (signaled bool) {
|
||||||
println("runtime: NtAssociateWaitCompletionPacket failed; errno=", errno)
|
println("runtime: NtAssociateWaitCompletionPacket failed; errno=", errno)
|
||||||
throw("runtime: netpoll failed")
|
throw("runtime: netpoll failed")
|
||||||
}
|
}
|
||||||
case STATUS_PENDING:
|
case windows.STATUS_PENDING:
|
||||||
// STATUS_PENDING is returned if the wait operation can't be canceled yet.
|
// 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,
|
// 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
|
// and the timer expired just while calling NtCancelWaitCompletionPacket, in which case
|
||||||
|
|
|
||||||
|
|
@ -323,7 +323,7 @@ func monitorSuspendResume() {
|
||||||
|
|
||||||
func getCPUCount() int32 {
|
func getCPUCount() int32 {
|
||||||
var mask, sysmask uintptr
|
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 {
|
if ret != 0 {
|
||||||
n := 0
|
n := 0
|
||||||
maskbits := int(unsafe.Sizeof(mask) * 8)
|
maskbits := int(unsafe.Sizeof(mask) * 8)
|
||||||
|
|
@ -337,22 +337,17 @@ func getCPUCount() int32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// use GetSystemInfo if GetProcessAffinityMask fails
|
// use GetSystemInfo if GetProcessAffinityMask fails
|
||||||
var info systeminfo
|
var info windows.SystemInfo
|
||||||
stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
|
stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
|
||||||
return int32(info.dwnumberofprocessors)
|
return int32(info.NumberOfProcessors)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPageSize() uintptr {
|
func getPageSize() uintptr {
|
||||||
var info systeminfo
|
var info windows.SystemInfo
|
||||||
stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
|
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:
|
// in sys_windows_386.s and sys_windows_amd64.s:
|
||||||
func getlasterror() uint32
|
func getlasterror() uint32
|
||||||
|
|
||||||
|
|
@ -405,18 +400,11 @@ var haveHighResSleep = false
|
||||||
// resolution timer. createHighResTimer returns new timer
|
// resolution timer. createHighResTimer returns new timer
|
||||||
// handle or 0, if CreateWaitableTimerEx failed.
|
// handle or 0, if CreateWaitableTimerEx failed.
|
||||||
func createHighResTimer() uintptr {
|
func createHighResTimer() uintptr {
|
||||||
const (
|
// As per @jstarks, see
|
||||||
// As per @jstarks, see
|
// https://github.com/golang/go/issues/8687#issuecomment-656259353
|
||||||
// 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
|
|
||||||
)
|
|
||||||
return stdcall(_CreateWaitableTimerExW, 0, 0,
|
return stdcall(_CreateWaitableTimerExW, 0, 0,
|
||||||
_CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
|
windows.CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
|
||||||
_SYNCHRONIZE|_TIMER_QUERY_STATE|_TIMER_MODIFY_STATE)
|
windows.SYNCHRONIZE|windows.TIMER_QUERY_STATE|windows.TIMER_MODIFY_STATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initHighResTimer() {
|
func initHighResTimer() {
|
||||||
|
|
@ -454,10 +442,10 @@ func initLongPathSupport() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check that we're ≥ 10.0.15063.
|
// Check that we're ≥ 10.0.15063.
|
||||||
info := _OSVERSIONINFOW{}
|
info := windows.OSVERSIONINFOW{}
|
||||||
info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
|
info.OSVersionInfoSize = uint32(unsafe.Sizeof(info))
|
||||||
stdcall(_RtlGetVersion, uintptr(unsafe.Pointer(&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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -493,7 +481,7 @@ func osinit() {
|
||||||
// of dedicated threads -- GUI, IO, computational, etc. Go processes use
|
// of dedicated threads -- GUI, IO, computational, etc. Go processes use
|
||||||
// equivalent threads that all do a mix of GUI, IO, computations, etc.
|
// 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.
|
// 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
|
//go:nosplit
|
||||||
|
|
@ -671,7 +659,7 @@ func semasleep(ns int64) int32 {
|
||||||
|
|
||||||
var result uintptr
|
var result uintptr
|
||||||
if ns < 0 {
|
if ns < 0 {
|
||||||
result = stdcall(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
|
result = stdcall(_WaitForSingleObject, getg().m.waitsema, uintptr(windows.INFINITE))
|
||||||
} else {
|
} else {
|
||||||
start := nanotime()
|
start := nanotime()
|
||||||
elapsed := int64(0)
|
elapsed := int64(0)
|
||||||
|
|
@ -828,7 +816,7 @@ func sigblock(exiting bool) {
|
||||||
// Called on the new thread, cannot allocate Go memory.
|
// Called on the new thread, cannot allocate Go memory.
|
||||||
func minit() {
|
func minit() {
|
||||||
var thandle uintptr
|
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")
|
print("runtime.minit: duplicatehandle failed; errno=", getlasterror(), "\n")
|
||||||
throw("runtime.minit: duplicatehandle failed")
|
throw("runtime.minit: duplicatehandle failed")
|
||||||
}
|
}
|
||||||
|
|
@ -863,7 +851,7 @@ func minit() {
|
||||||
|
|
||||||
// Query the true stack base from the OS. Currently we're
|
// Query the true stack base from the OS. Currently we're
|
||||||
// running on a small assumed stack.
|
// 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))
|
res := stdcall(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
|
print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
|
||||||
|
|
@ -875,7 +863,7 @@ func minit() {
|
||||||
// calling C functions that don't have stack checks and for
|
// calling C functions that don't have stack checks and for
|
||||||
// lastcontinuehandler. We shouldn't be anywhere near this
|
// lastcontinuehandler. We shouldn't be anywhere near this
|
||||||
// bound anyway.
|
// bound anyway.
|
||||||
base := mbi.allocationBase + 16<<10
|
base := mbi.AllocationBase + 16<<10
|
||||||
// Sanity check the stack bounds.
|
// Sanity check the stack bounds.
|
||||||
g0 := getg()
|
g0 := getg()
|
||||||
if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
|
if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
|
||||||
|
|
@ -1000,7 +988,7 @@ func osyield() {
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func usleep_no_g(us uint32) {
|
func usleep_no_g(us uint32) {
|
||||||
timeout := uintptr(us) / 1000 // ms units
|
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
|
//go:nosplit
|
||||||
|
|
@ -1013,9 +1001,9 @@ func usleep(us uint32) {
|
||||||
h = getg().m.highResTimer
|
h = getg().m.highResTimer
|
||||||
dt := -10 * int64(us) // relative sleep (negative), 100ns units
|
dt := -10 * int64(us) // relative sleep (negative), 100ns units
|
||||||
stdcall(_SetWaitableTimer, h, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0)
|
stdcall(_SetWaitableTimer, h, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0)
|
||||||
timeout = _INFINITE
|
timeout = windows.INFINITE
|
||||||
} else {
|
} else {
|
||||||
h = _INVALID_HANDLE_VALUE
|
h = windows.INVALID_HANDLE_VALUE
|
||||||
timeout = uintptr(us) / 1000 // ms units
|
timeout = uintptr(us) / 1000 // ms units
|
||||||
}
|
}
|
||||||
stdcall(_WaitForSingleObject, h, timeout)
|
stdcall(_WaitForSingleObject, h, timeout)
|
||||||
|
|
@ -1026,16 +1014,16 @@ func ctrlHandler(_type uint32) uintptr {
|
||||||
var s uint32
|
var s uint32
|
||||||
|
|
||||||
switch _type {
|
switch _type {
|
||||||
case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
|
case windows.CTRL_C_EVENT, windows.CTRL_BREAK_EVENT:
|
||||||
s = _SIGINT
|
s = windows.SIGINT
|
||||||
case _CTRL_CLOSE_EVENT, _CTRL_LOGOFF_EVENT, _CTRL_SHUTDOWN_EVENT:
|
case windows.CTRL_CLOSE_EVENT, windows.CTRL_LOGOFF_EVENT, windows.CTRL_SHUTDOWN_EVENT:
|
||||||
s = _SIGTERM
|
s = windows.SIGTERM
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if sigsend(s) {
|
if sigsend(s) {
|
||||||
if s == _SIGTERM {
|
if s == windows.SIGTERM {
|
||||||
// Windows terminates the process after this handler returns.
|
// Windows terminates the process after this handler returns.
|
||||||
// Block indefinitely to give signal handlers a chance to clean up,
|
// Block indefinitely to give signal handlers a chance to clean up,
|
||||||
// but make sure to be properly parked first, so the rest of the
|
// 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) {
|
func profilem(mp *m, thread uintptr) {
|
||||||
// Align Context to 16 bytes.
|
// Align Context to 16 bytes.
|
||||||
var c *context
|
var c *windows.Context
|
||||||
var cbuf [unsafe.Sizeof(*c) + 15]byte
|
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)))
|
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 gFromSP(mp *m, sp uintptr) *g {
|
||||||
|
|
@ -1080,10 +1068,10 @@ func gFromSP(mp *m, sp uintptr) *g {
|
||||||
}
|
}
|
||||||
|
|
||||||
func profileLoop() {
|
func profileLoop() {
|
||||||
stdcall(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
|
stdcall(_SetThreadPriority, windows.CurrentThread, windows.THREAD_PRIORITY_HIGHEST)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
stdcall(_WaitForSingleObject, profiletimer, _INFINITE)
|
stdcall(_WaitForSingleObject, profiletimer, windows.INFINITE)
|
||||||
first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
|
first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
|
||||||
for mp := first; mp != nil; mp = mp.alllink {
|
for mp := first; mp != nil; mp = mp.alllink {
|
||||||
if mp == getg().m {
|
if mp == getg().m {
|
||||||
|
|
@ -1101,7 +1089,7 @@ func profileLoop() {
|
||||||
}
|
}
|
||||||
// Acquire our own handle to the thread.
|
// Acquire our own handle to the thread.
|
||||||
var thread uintptr
|
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")
|
print("runtime: duplicatehandle failed; errno=", getlasterror(), "\n")
|
||||||
throw("duplicatehandle failed")
|
throw("duplicatehandle failed")
|
||||||
}
|
}
|
||||||
|
|
@ -1183,17 +1171,17 @@ func preemptM(mp *m) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var thread uintptr
|
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")
|
print("runtime.preemptM: duplicatehandle failed; errno=", getlasterror(), "\n")
|
||||||
throw("runtime.preemptM: duplicatehandle failed")
|
throw("runtime.preemptM: duplicatehandle failed")
|
||||||
}
|
}
|
||||||
unlock(&mp.threadLock)
|
unlock(&mp.threadLock)
|
||||||
|
|
||||||
// Prepare thread context buffer. This must be aligned to 16 bytes.
|
// 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
|
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
|
||||||
|
|
||||||
// Serialize thread suspension. SuspendThread is asynchronous,
|
// Serialize thread suspension. SuspendThread is asynchronous,
|
||||||
// so it's otherwise possible for two threads to suspend each
|
// so it's otherwise possible for two threads to suspend each
|
||||||
|
|
@ -1227,12 +1215,12 @@ func preemptM(mp *m) {
|
||||||
unlock(&suspendLock)
|
unlock(&suspendLock)
|
||||||
|
|
||||||
// Does it want a preemption and is it safe to preempt?
|
// 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 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
|
// Inject call to asyncPreempt
|
||||||
targetPC := abi.FuncPCABI0(asyncPreempt)
|
targetPC := abi.FuncPCABI0(asyncPreempt)
|
||||||
c.pushCall(targetPC, resumePC)
|
c.PushCall(targetPC, resumePC)
|
||||||
stdcall(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
|
stdcall(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,7 @@ func cputicks() int64 {
|
||||||
stdcall(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
|
stdcall(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
|
||||||
return counter
|
return counter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stackcheck() {
|
||||||
|
// TODO: not implemented
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ package runtime_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
|
"internal/runtime/sys"
|
||||||
"internal/syscall/windows"
|
"internal/syscall/windows"
|
||||||
"runtime"
|
"runtime"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
@ -47,7 +48,7 @@ func TestSehLookupFunctionEntry(t *testing.T) {
|
||||||
{"func in prologue", sehf1pc + 1, true},
|
{"func in prologue", sehf1pc + 1, true},
|
||||||
{"anonymous func with frame", abi.FuncPCABIInternal(fnwithframe), true},
|
{"anonymous func with frame", abi.FuncPCABIInternal(fnwithframe), true},
|
||||||
{"anonymous func without frame", abi.FuncPCABIInternal(fnwithoutframe), false},
|
{"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 {
|
for _, tt := range tests {
|
||||||
var base uintptr
|
var base uintptr
|
||||||
|
|
@ -68,19 +69,22 @@ func sehCallers() []uintptr {
|
||||||
// We don't need a real context,
|
// We don't need a real context,
|
||||||
// RtlVirtualUnwind just needs a context with
|
// RtlVirtualUnwind just needs a context with
|
||||||
// valid a pc, sp and fp (aka bp).
|
// 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)
|
pcs := make([]uintptr, 15)
|
||||||
var base, frame uintptr
|
var base, frame uintptr
|
||||||
var n int
|
var n int
|
||||||
for i := 0; i < len(pcs); i++ {
|
for i := 0; i < len(pcs); i++ {
|
||||||
fn := windows.RtlLookupFunctionEntry(ctx.GetPC(), &base, nil)
|
fn := windows.RtlLookupFunctionEntry(ctx.PC(), &base, nil)
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
pcs[i] = ctx.GetPC()
|
pcs[i] = ctx.PC()
|
||||||
n++
|
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]
|
return pcs[:n]
|
||||||
}
|
}
|
||||||
|
|
@ -129,15 +133,14 @@ func TestSehUnwind(t *testing.T) {
|
||||||
t.Skip("skipping amd64-only test")
|
t.Skip("skipping amd64-only test")
|
||||||
}
|
}
|
||||||
pcs := sehf3(false)
|
pcs := sehf3(false)
|
||||||
testSehCallersEqual(t, pcs, []string{"runtime_test.sehCallers", "runtime_test.sehf4",
|
testSehCallersEqual(t, pcs, []string{"runtime_test.sehf4", "runtime_test.sehf3", "runtime_test.TestSehUnwind"})
|
||||||
"runtime_test.sehf3", "runtime_test.TestSehUnwind"})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSehUnwindPanic(t *testing.T) {
|
func TestSehUnwindPanic(t *testing.T) {
|
||||||
if runtime.GOARCH != "amd64" {
|
if runtime.GOARCH != "amd64" {
|
||||||
t.Skip("skipping amd64-only test")
|
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"}
|
"runtime_test.sehf4", "runtime_test.sehf3", "runtime_test.TestSehUnwindPanic"}
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r == nil {
|
if r := recover(); r == nil {
|
||||||
|
|
@ -153,7 +156,7 @@ func TestSehUnwindDoublePanic(t *testing.T) {
|
||||||
if runtime.GOARCH != "amd64" {
|
if runtime.GOARCH != "amd64" {
|
||||||
t.Skip("skipping amd64-only test")
|
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"}
|
"runtime_test.TestSehUnwindDoublePanic.func1", "runtime.gopanic", "runtime_test.TestSehUnwindDoublePanic"}
|
||||||
defer func() {
|
defer func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
@ -175,7 +178,7 @@ func TestSehUnwindNilPointerPanic(t *testing.T) {
|
||||||
if runtime.GOARCH != "amd64" {
|
if runtime.GOARCH != "amd64" {
|
||||||
t.Skip("skipping amd64-only test")
|
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"}
|
"runtime.sigpanic", "runtime_test.TestSehUnwindNilPointerPanic"}
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r == nil {
|
if r := recover(); r == nil {
|
||||||
|
|
|
||||||
|
|
@ -6,36 +6,29 @@ package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
|
"internal/runtime/syscall/windows"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
_SEM_FAILCRITICALERRORS = 0x0001
|
|
||||||
_SEM_NOGPFAULTERRORBOX = 0x0002
|
|
||||||
_SEM_NOOPENFILEERRORBOX = 0x8000
|
|
||||||
|
|
||||||
_WER_FAULT_REPORTING_NO_UI = 0x0020
|
|
||||||
)
|
|
||||||
|
|
||||||
func preventErrorDialogs() {
|
func preventErrorDialogs() {
|
||||||
errormode := stdcall(_GetErrorMode)
|
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.
|
// Disable WER fault reporting UI.
|
||||||
// Do this even if WER is disabled as a whole,
|
// Do this even if WER is disabled as a whole,
|
||||||
// as WER might be enabled later with setTraceback("wer")
|
// as WER might be enabled later with setTraceback("wer")
|
||||||
// and we still want the fault reporting UI to be disabled if this happens.
|
// and we still want the fault reporting UI to be disabled if this happens.
|
||||||
var werflags uintptr
|
var werflags uintptr
|
||||||
stdcall(_WerGetFlags, currentProcess, uintptr(unsafe.Pointer(&werflags)))
|
stdcall(_WerGetFlags, windows.CurrentProcess, uintptr(unsafe.Pointer(&werflags)))
|
||||||
stdcall(_WerSetFlags, werflags|_WER_FAULT_REPORTING_NO_UI)
|
stdcall(_WerSetFlags, werflags|windows.WER_FAULT_REPORTING_NO_UI)
|
||||||
}
|
}
|
||||||
|
|
||||||
// enableWER re-enables Windows error reporting without fault reporting UI.
|
// enableWER re-enables Windows error reporting without fault reporting UI.
|
||||||
func enableWER() {
|
func enableWER() {
|
||||||
// re-enable Windows Error Reporting
|
// re-enable Windows Error Reporting
|
||||||
errormode := stdcall(_GetErrorMode)
|
errormode := stdcall(_GetErrorMode)
|
||||||
if errormode&_SEM_NOGPFAULTERRORBOX != 0 {
|
if errormode&windows.SEM_NOGPFAULTERRORBOX != 0 {
|
||||||
stdcall(_SetErrorMode, errormode^_SEM_NOGPFAULTERRORBOX)
|
stdcall(_SetErrorMode, errormode^windows.SEM_NOGPFAULTERRORBOX)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,8 +55,8 @@ func initExceptionHandler() {
|
||||||
// by calling runtime.abort function.
|
// by calling runtime.abort function.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func isAbort(r *context) bool {
|
func isAbort(r *windows.Context) bool {
|
||||||
pc := r.ip()
|
pc := r.PC()
|
||||||
if GOARCH == "386" || GOARCH == "amd64" {
|
if GOARCH == "386" || GOARCH == "amd64" {
|
||||||
// In the case of an abort, the exception IP is one byte after
|
// In the case of an abort, the exception IP is one byte after
|
||||||
// the INT3 (this differs from UNIX OSes).
|
// the INT3 (this differs from UNIX OSes).
|
||||||
|
|
@ -79,29 +72,29 @@ func isAbort(r *context) bool {
|
||||||
// because of a stack overflow.
|
// because of a stack overflow.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//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
|
// Only handle exception if executing instructions in Go binary
|
||||||
// (not Windows library code).
|
// (not Windows library code).
|
||||||
// TODO(mwhudson): needs to loop to support shared libs
|
// 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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go will only handle some exceptions.
|
// Go will only handle some exceptions.
|
||||||
switch info.exceptioncode {
|
switch info.ExceptionCode {
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
case _EXCEPTION_ACCESS_VIOLATION:
|
case windows.EXCEPTION_ACCESS_VIOLATION:
|
||||||
case _EXCEPTION_IN_PAGE_ERROR:
|
case windows.EXCEPTION_IN_PAGE_ERROR:
|
||||||
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
|
case windows.EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||||
case _EXCEPTION_INT_OVERFLOW:
|
case windows.EXCEPTION_INT_OVERFLOW:
|
||||||
case _EXCEPTION_FLT_DENORMAL_OPERAND:
|
case windows.EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||||
case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
case windows.EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||||
case _EXCEPTION_FLT_INEXACT_RESULT:
|
case windows.EXCEPTION_FLT_INEXACT_RESULT:
|
||||||
case _EXCEPTION_FLT_OVERFLOW:
|
case windows.EXCEPTION_FLT_OVERFLOW:
|
||||||
case _EXCEPTION_FLT_UNDERFLOW:
|
case windows.EXCEPTION_FLT_UNDERFLOW:
|
||||||
case _EXCEPTION_BREAKPOINT:
|
case windows.EXCEPTION_BREAKPOINT:
|
||||||
case _EXCEPTION_ILLEGAL_INSTRUCTION: // breakpoint arrives this way on arm64
|
case windows.EXCEPTION_ILLEGAL_INSTRUCTION: // breakpoint arrives this way on arm64
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -134,13 +127,13 @@ func sigFetchG() *g {
|
||||||
// It is nosplit for the same reason as exceptionhandler.
|
// It is nosplit for the same reason as exceptionhandler.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func sigtrampgo(ep *exceptionpointers, kind int) int32 {
|
func sigtrampgo(ep *windows.ExceptionPointers, kind int) int32 {
|
||||||
gp := sigFetchG()
|
gp := sigFetchG()
|
||||||
if gp == nil {
|
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 {
|
switch kind {
|
||||||
case callbackVEH:
|
case callbackVEH:
|
||||||
fn = exceptionhandler
|
fn = exceptionhandler
|
||||||
|
|
@ -169,12 +162,12 @@ func sigtrampgo(ep *exceptionpointers, kind int) int32 {
|
||||||
var ret int32
|
var ret int32
|
||||||
if gp != gp.m.g0 {
|
if gp != gp.m.g0 {
|
||||||
systemstack(func() {
|
systemstack(func() {
|
||||||
ret = fn(ep.record, ep.context, gp)
|
ret = fn(ep.Record, ep.Context, gp)
|
||||||
})
|
})
|
||||||
} else {
|
} 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
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,13 +182,13 @@ func sigtrampgo(ep *exceptionpointers, kind int) int32 {
|
||||||
// will not actually return to the original frame, so the registers
|
// will not actually return to the original frame, so the registers
|
||||||
// are effectively dead. But this does mean we can't use the
|
// are effectively dead. But this does mean we can't use the
|
||||||
// same mechanism for async preemption.
|
// 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.
|
// sigresume has already been set up by a previous exception.
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
prepareContextForSigResume(ep.context)
|
prepareContextForSigResume(ep.Context)
|
||||||
ep.context.set_sp(gp.m.g0.sched.sp)
|
ep.Context.SetSP(gp.m.g0.sched.sp)
|
||||||
ep.context.set_ip(abi.FuncPCABI0(sigresume))
|
ep.Context.SetPC(abi.FuncPCABI0(sigresume))
|
||||||
return ret
|
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.
|
// _EXCEPTION_BREAKPOINT, which is raised by abort() if we overflow the g0 stack.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//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) {
|
if !isgoexception(info, r) {
|
||||||
return _EXCEPTION_CONTINUE_SEARCH
|
return windows.EXCEPTION_CONTINUE_SEARCH
|
||||||
}
|
}
|
||||||
|
|
||||||
if gp.throwsplit || isAbort(r) {
|
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
|
// Have to pass arguments out of band since
|
||||||
// augmenting the stack frame would break
|
// augmenting the stack frame would break
|
||||||
// the unwinding code.
|
// the unwinding code.
|
||||||
gp.sig = info.exceptioncode
|
gp.sig = info.ExceptionCode
|
||||||
gp.sigcode0 = info.exceptioninformation[0]
|
gp.sigcode0 = info.ExceptionInformation[0]
|
||||||
gp.sigcode1 = info.exceptioninformation[1]
|
gp.sigcode1 = info.ExceptionInformation[1]
|
||||||
gp.sigpc = r.ip()
|
gp.sigpc = r.PC()
|
||||||
|
|
||||||
// Only push runtime·sigpanic if r.ip() != 0.
|
// Only push runtime·sigpanic if r.ip() != 0.
|
||||||
// If r.ip() == 0, probably panicked because of a
|
// 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
|
// The exception is not from asyncPreempt, so not to push a
|
||||||
// sigpanic call to make it look like that. Instead, just
|
// sigpanic call to make it look like that. Instead, just
|
||||||
// overwrite the PC. (See issue #35773)
|
// overwrite the PC. (See issue #35773)
|
||||||
if r.ip() != 0 && r.ip() != abi.FuncPCABI0(asyncPreempt) {
|
if r.PC() != 0 && r.PC() != abi.FuncPCABI0(asyncPreempt) {
|
||||||
r.pushCall(abi.FuncPCABI0(sigpanic0), r.ip())
|
r.PushCall(abi.FuncPCABI0(sigpanic0), r.PC())
|
||||||
} else {
|
} else {
|
||||||
// Not safe to push the call. Just clobber the frame.
|
// 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.
|
// 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.
|
// It is nosplit for the same reason as exceptionhandler.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//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()
|
g0 := getg()
|
||||||
if g0 == nil || g0.m.curg == nil {
|
if g0 == nil || g0.m.curg == nil {
|
||||||
// No g available, nothing to do here.
|
// 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
|
// The Windows SEH machinery will unwind the stack until it finds
|
||||||
// a frame with a handler for the exception or until the frame is
|
// 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
|
// 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.
|
// stack is reached, and then pass the control back to Windows.
|
||||||
gp := g0.m.curg
|
gp := g0.m.curg
|
||||||
ctxt := dctxt.ctx()
|
ctxt := dctxt.Ctx()
|
||||||
var base, sp uintptr
|
var base, sp uintptr
|
||||||
for {
|
for {
|
||||||
entry := stdcall(_RtlLookupFunctionEntry, ctxt.ip(), uintptr(unsafe.Pointer(&base)), 0)
|
entry := stdcall(_RtlLookupFunctionEntry, ctxt.PC(), uintptr(unsafe.Pointer(&base)), 0)
|
||||||
if entry == 0 {
|
if entry == 0 {
|
||||||
break
|
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 {
|
if sp < gp.stack.lo || gp.stack.hi <= sp {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _EXCEPTION_CONTINUE_SEARCH_SEH
|
return windows.EXCEPTION_CONTINUE_SEARCH_SEH
|
||||||
}
|
}
|
||||||
|
|
||||||
// It seems Windows searches ContinueHandler's list even
|
// 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.
|
// It is nosplit for the same reason as exceptionhandler.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//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) {
|
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
|
// 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.
|
// It is nosplit for the same reason as exceptionhandler.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//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 {
|
if islibrary || isarchive {
|
||||||
// Go DLL/archive has been loaded in a non-go program.
|
// Go DLL/archive has been loaded in a non-go program.
|
||||||
// If the exception does not originate from go, the go runtime
|
// If the exception does not originate from go, the go runtime
|
||||||
// should not take responsibility of crashing the process.
|
// 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
|
// 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
|
// arm64 and it's an illegal instruction and this is coming from
|
||||||
// non-Go code, then assume it's this runtime probing happen, and
|
// non-Go code, then assume it's this runtime probing happen, and
|
||||||
// pass that onward to SEH.
|
// pass that onward to SEH.
|
||||||
if GOARCH == "arm64" && info.exceptioncode == _EXCEPTION_ILLEGAL_INSTRUCTION &&
|
if GOARCH == "arm64" && info.ExceptionCode == windows.EXCEPTION_ILLEGAL_INSTRUCTION &&
|
||||||
(r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip()) {
|
(r.PC() < firstmoduledata.text || firstmoduledata.etext < r.PC()) {
|
||||||
return _EXCEPTION_CONTINUE_SEARCH
|
return windows.EXCEPTION_CONTINUE_SEARCH
|
||||||
}
|
}
|
||||||
|
|
||||||
winthrow(info, r, gp)
|
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.
|
// Always called on g0. gp is the G where the exception occurred.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func winthrow(info *exceptionrecord, r *context, gp *g) {
|
func winthrow(info *windows.ExceptionRecord, r *windows.Context, gp *g) {
|
||||||
g0 := getg()
|
g0 := getg()
|
||||||
|
|
||||||
if panicking.Load() != 0 { // traceback already printed
|
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.stackguard0 = g0.stack.lo + stackGuard
|
||||||
g0.stackguard1 = g0.stackguard0
|
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 g0.m.incgo && gp == g0.m.g0 && g0.m.curg != nil {
|
||||||
if iscgo {
|
if iscgo {
|
||||||
print("signal arrived during external code execution\n")
|
print("signal arrived during external code execution\n")
|
||||||
|
|
@ -368,7 +361,7 @@ func winthrow(info *exceptionrecord, r *context, gp *g) {
|
||||||
|
|
||||||
level, _, docrash := gotraceback()
|
level, _, docrash := gotraceback()
|
||||||
if level > 0 {
|
if level > 0 {
|
||||||
tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
|
tracebacktrap(r.PC(), r.SP(), r.LR(), gp)
|
||||||
tracebackothers(gp)
|
tracebackothers(gp)
|
||||||
dumpregs(r)
|
dumpregs(r)
|
||||||
}
|
}
|
||||||
|
|
@ -387,7 +380,7 @@ func sigpanic() {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch gp.sig {
|
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 {
|
if gp.sigcode1 < 0x1000 {
|
||||||
panicmem()
|
panicmem()
|
||||||
}
|
}
|
||||||
|
|
@ -403,15 +396,15 @@ func sigpanic() {
|
||||||
print("unexpected fault address ", hex(gp.sigcode1), "\n")
|
print("unexpected fault address ", hex(gp.sigcode1), "\n")
|
||||||
}
|
}
|
||||||
throw("fault")
|
throw("fault")
|
||||||
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
|
case windows.EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||||
panicdivide()
|
panicdivide()
|
||||||
case _EXCEPTION_INT_OVERFLOW:
|
case windows.EXCEPTION_INT_OVERFLOW:
|
||||||
panicoverflow()
|
panicoverflow()
|
||||||
case _EXCEPTION_FLT_DENORMAL_OPERAND,
|
case windows.EXCEPTION_FLT_DENORMAL_OPERAND,
|
||||||
_EXCEPTION_FLT_DIVIDE_BY_ZERO,
|
windows.EXCEPTION_FLT_DIVIDE_BY_ZERO,
|
||||||
_EXCEPTION_FLT_INEXACT_RESULT,
|
windows.EXCEPTION_FLT_INEXACT_RESULT,
|
||||||
_EXCEPTION_FLT_OVERFLOW,
|
windows.EXCEPTION_FLT_OVERFLOW,
|
||||||
_EXCEPTION_FLT_UNDERFLOW:
|
windows.EXCEPTION_FLT_UNDERFLOW:
|
||||||
panicfloat()
|
panicfloat()
|
||||||
}
|
}
|
||||||
throw("fault")
|
throw("fault")
|
||||||
|
|
@ -444,29 +437,28 @@ func crash() {
|
||||||
// This provides the expected exit status for the shell.
|
// This provides the expected exit status for the shell.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func dieFromException(info *exceptionrecord, r *context) {
|
func dieFromException(info *windows.ExceptionRecord, r *windows.Context) {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
gp := getg()
|
gp := getg()
|
||||||
if gp.sig != 0 {
|
if gp.sig != 0 {
|
||||||
// Try to reconstruct an exception record from
|
// Try to reconstruct an exception record from
|
||||||
// the exception information stored in gp.
|
// the exception information stored in gp.
|
||||||
info = &exceptionrecord{
|
info = &windows.ExceptionRecord{
|
||||||
exceptionaddress: gp.sigpc,
|
ExceptionAddress: gp.sigpc,
|
||||||
exceptioncode: gp.sig,
|
ExceptionCode: gp.sig,
|
||||||
numberparameters: 2,
|
NumberParameters: 2,
|
||||||
}
|
}
|
||||||
info.exceptioninformation[0] = gp.sigcode0
|
info.ExceptionInformation[0] = gp.sigcode0
|
||||||
info.exceptioninformation[1] = gp.sigcode1
|
info.ExceptionInformation[1] = gp.sigcode1
|
||||||
} else {
|
} else {
|
||||||
// By default, a failing Go application exits with exit code 2.
|
// By default, a failing Go application exits with exit code 2.
|
||||||
// Use this value when gp does not contain exception info.
|
// Use this value when gp does not contain exception info.
|
||||||
info = &exceptionrecord{
|
info = &windows.ExceptionRecord{
|
||||||
exceptioncode: 2,
|
ExceptionCode: 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const FAIL_FAST_GENERATE_EXCEPTION_ADDRESS = 0x1
|
stdcall(_RaiseFailFastException, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(r)), windows.FAIL_FAST_GENERATE_EXCEPTION_ADDRESS)
|
||||||
stdcall(_RaiseFailFastException, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(r)), FAIL_FAST_GENERATE_EXCEPTION_ADDRESS)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// gsignalStack is unused on Windows.
|
// gsignalStack is unused on Windows.
|
||||||
|
|
|
||||||
28
src/runtime/signal_windows_386.go
Normal file
28
src/runtime/signal_windows_386.go
Normal file
|
|
@ -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")
|
||||||
|
}
|
||||||
36
src/runtime/signal_windows_amd64.go
Normal file
36
src/runtime/signal_windows_amd64.go
Normal file
|
|
@ -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")
|
||||||
|
}
|
||||||
49
src/runtime/signal_windows_arm64.go
Normal file
49
src/runtime/signal_windows_arm64.go
Normal file
|
|
@ -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")
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue