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
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,3 +12,7 @@ func cputicks() int64 {
|
|||
stdcall(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
|
||||
return counter
|
||||
}
|
||||
|
||||
func stackcheck() {
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
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