57 lines
1.7 KiB
Go
57 lines
1.7 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package verify
|
|
|
|
// abiResult records register-clobber violations detected by the ABI-checking
|
|
// trampolines. Bit 0: frame pointer clobbered. Bit 1: goroutine pointer
|
|
// clobbered.
|
|
var abiResult uint64
|
|
|
|
// ABIReport describes the result of an ABI-checking call. The register
|
|
// fields are architecture-dependent:
|
|
//
|
|
// - FPClobbered: the frame pointer the Go runtime maintains
|
|
// (amd64 BP, arm64 R29). riscv64 and loong64 keep no hardware frame
|
|
// pointer, so the field is always false there.
|
|
// - GClobbered: the goroutine pointer (amd64 R14, arm64 R28,
|
|
// riscv64 X27, loong64 R22).
|
|
type ABIReport struct {
|
|
FPClobbered bool
|
|
GClobbered bool
|
|
RedZoneHit bool
|
|
}
|
|
|
|
// OK returns true when no violations were detected.
|
|
func (r ABIReport) OK() bool {
|
|
return !r.FPClobbered && !r.GClobbered && !r.RedZoneHit
|
|
}
|
|
|
|
// String returns a human-readable summary.
|
|
func (r ABIReport) String() string {
|
|
if r.OK() {
|
|
return "ABI clean"
|
|
}
|
|
s := "ABI violation:"
|
|
if r.FPClobbered {
|
|
s += " frame pointer clobbered"
|
|
}
|
|
if r.GClobbered {
|
|
s += " goroutine pointer clobbered"
|
|
}
|
|
if r.RedZoneHit {
|
|
s += " stack below SP written"
|
|
}
|
|
return s
|
|
}
|
|
|
|
// redZoneSize is the canary window below the prepared stack pointer. On
|
|
// amd64 it is the System V red zone; on every architecture a Go function
|
|
// must not write below its own declared frame, so the canary sits below
|
|
// the frame plus the call margin (see CallCheckedFrame) and any corruption
|
|
// there is a bug.
|
|
const redZoneSize = 128
|
|
|
|
// redZoneFill is the byte pattern used to detect writes below SP.
|
|
const redZoneFill = 0xA5
|