Refactor nogo and provide facts render.

This change makes the core nogo package less of a "catch all", and splits
functionality into multiple packages. Instead of separate binaries for each
function, a single "cli" package is added with subcommands, and the core
starlark wrappers are also refactored to minimize redundancy.

The new "cli" package also adds support for a "render" command, which
allows factors to be rendered via a Go text template. This is useful for
debugging, but also allows code generation to be updated to use this
mechanism. This eliminates the use of a QEMU wrapper for the older
arch_genrule, and allows the use of a native bazel transition to extract
facts for the appropriate generated file. In other words, the correct facts
will be rendered for generating XXX_arm64.s, even on amd64.

PiperOrigin-RevId: 422846459
This commit is contained in:
Adin Scannell
2022-01-19 10:26:27 -08:00
committed by gVisor bot
parent 3d578afc8d
commit 0e492a2b5e
51 changed files with 3239 additions and 2216 deletions
+1 -1
View File
@@ -54,7 +54,7 @@ doc(
yaml_test( yaml_test(
name = "nogo_config_test", name = "nogo_config_test",
srcs = glob(["nogo*.yaml"]), srcs = glob(["nogo*.yaml"]),
schema = "//tools/nogo:config-schema.json", schema = "//tools/nogo/config:schema.json",
) )
yaml_test( yaml_test(
+1 -1
View File
@@ -196,7 +196,7 @@ nogo-tests:
# For unit tests, we take everything in the root, pkg/... and tools/..., and # For unit tests, we take everything in the root, pkg/... and tools/..., and
# pull in all directories in runsc except runsc/container. # pull in all directories in runsc except runsc/container.
unit-tests: ## Local package unit tests in pkg/..., tools/.., etc. unit-tests: ## Local package unit tests in pkg/..., tools/.., etc.
@$(call test,--build_tag_filters=-nogo --test_tag_filters=-nogo --test_filter=-//runsc/container/... //:all pkg/... tools/... runsc/...) @$(call test,--build_tag_filters=-nogo --test_tag_filters=-nogo --test_filter=-//runsc/container/... //:all pkg/... tools/... runsc/... vdso/...)
.PHONY: unit-tests .PHONY: unit-tests
# See unit-tests: this includes runsc/container. # See unit-tests: this includes runsc/container.
-9
View File
@@ -36,8 +36,6 @@ http_archive(
name = "io_bazel_rules_go", name = "io_bazel_rules_go",
patch_args = ["-p1"], patch_args = ["-p1"],
patches = [ patches = [
# Ensure we don't destroy the facts visibility.
"//tools:rules_go_visibility.patch",
# Newer versions of the rules_go rules will automatically strip test # Newer versions of the rules_go rules will automatically strip test
# binaries of symbols, which we don't want. # binaries of symbols, which we don't want.
"//tools:rules_go_symbols.patch", "//tools:rules_go_symbols.patch",
@@ -51,13 +49,6 @@ http_archive(
http_archive( http_archive(
name = "bazel_gazelle", name = "bazel_gazelle",
patch_args = ["-p1"],
patches = [
# Fix permissions for facts for go_library, not just tool library.
# This is actually a no-op with the hacky patch above, but should
# slightly future proof this mechanism.
"//tools:bazel_gazelle_generate.patch",
],
sha256 = "62ca106be173579c0a167deb23358fdfe71ffa1e4cfdddf5582af26520f1c66f", sha256 = "62ca106be173579c0a167deb23358fdfe71ffa1e4cfdddf5582af26520f1c66f",
urls = [ urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz", "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
+30 -49
View File
@@ -1,69 +1,50 @@
load("//tools:defs.bzl", "arch_genrule", "go_library") load("//tools:defs.bzl", "arch_genrule", "go_library", "select_arch")
load("//tools/go_generics:defs.bzl", "go_template", "go_template_instance") load("//tools/nogo:defs.bzl", "nogo_facts")
package(licenses = ["notice"]) package(licenses = ["notice"])
go_template( exports_files(glob(["*.go"]))
name = "defs_amd64",
srcs = [
"defs.go",
"defs_amd64.go",
"offsets_amd64.go",
"x86.go",
],
visibility = [":__subpackages__"],
)
go_template( nogo_facts(
name = "defs_arm64", name = "entry_impl",
srcs = [ srcs = [
"aarch64.go", "aarch64.go",
"defs.go", "defs.go",
"defs_amd64.go",
"defs_arm64.go", "defs_arm64.go",
"offsets_arm64.go", "entry_template.go",
"x86.go",
],
output = "entry_impl.s",
template = select_arch(
amd64 = "entry_amd64.s",
arm64 = "entry_arm64.s",
),
deps = [
"//pkg/abi/linux",
"//pkg/cpuid",
"//pkg/hostarch",
"//pkg/ring0/pagetables",
"//pkg/sentry/arch",
"//pkg/sentry/arch/fpu",
], ],
visibility = [":__subpackages__"],
)
go_template_instance(
name = "defs_impl_amd64",
out = "defs_impl_amd64.go",
package = "ring0",
template = ":defs_amd64",
)
go_template_instance(
name = "defs_impl_arm64",
out = "defs_impl_arm64.go",
package = "ring0",
template = ":defs_arm64",
) )
arch_genrule( arch_genrule(
name = "entry_impl_amd64", name = "entry_impl_arch",
srcs = ["entry_amd64.s"], src = ":entry_impl",
outs = ["entry_impl_amd64.s"], template = "entry_impl_%s.s",
cmd = "(echo -e '// build +amd64\\n' && QEMU $(location //pkg/ring0/gen_offsets) && cat $(location entry_amd64.s)) > $@",
tools = ["//pkg/ring0/gen_offsets"],
)
arch_genrule(
name = "entry_impl_arm64",
srcs = ["entry_arm64.s"],
outs = ["entry_impl_arm64.s"],
cmd = "(echo -e '// build +arm64\\n' && QEMU $(location //pkg/ring0/gen_offsets) && cat $(location entry_arm64.s)) > $@",
tools = ["//pkg/ring0/gen_offsets"],
) )
go_library( go_library(
name = "ring0", name = "ring0",
srcs = [ srcs = [
"defs_impl_amd64.go", "aarch64.go",
"defs_impl_arm64.go", "defs.go",
"defs_amd64.go",
"defs_arm64.go",
"entry_amd64.go", "entry_amd64.go",
"entry_arm64.go", "entry_arm64.go",
"entry_impl_amd64.s",
"entry_impl_arm64.s",
"kernel.go", "kernel.go",
"kernel_amd64.go", "kernel_amd64.go",
"kernel_arm64.go", "kernel_arm64.go",
@@ -73,15 +54,15 @@ go_library(
"lib_arm64.go", "lib_arm64.go",
"lib_arm64.s", "lib_arm64.s",
"ring0.go", "ring0.go",
"x86.go",
":entry_impl_arch",
], ],
visibility = ["//pkg/sentry:internal"], visibility = ["//pkg/sentry:internal"],
deps = [ deps = [
"//pkg/cpuid", "//pkg/cpuid",
"//pkg/hostarch", "//pkg/hostarch",
"//pkg/ring0/pagetables", "//pkg/ring0/pagetables",
"//pkg/safecopy",
"//pkg/sentry/arch", "//pkg/sentry/arch",
"//pkg/sentry/arch/fpu", "//pkg/sentry/arch/fpu",
"//pkg/sync",
], ],
) )
-3
View File
@@ -137,6 +137,3 @@ type SwitchArchOpts struct {
// KernelASID indicates that the kernel ASID to be used on return, // KernelASID indicates that the kernel ASID to be used on return,
KernelASID uint16 KernelASID uint16
} }
func init() {
}
+71 -3
View File
@@ -15,9 +15,77 @@
#include "funcdata.h" #include "funcdata.h"
#include "textflag.h" #include "textflag.h"
// NB: Offsets are programmatically generated (see BUILD). // CPU offsets.
// #define CPU_REGISTERS {{ .CPU.registers.Offset }}
// This file is concatenated with the definitions. #define CPU_FPU_STATE {{ .CPU.floatingPointState.Offset }}
#define CPU_ERROR_CODE ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.errorCode.Offset }})
#define CPU_ERROR_TYPE ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.errorType.Offset }})
#define CPU_ENTRY ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.kernelEntry.Offset }})
#define CPU_HAS_XSAVE ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.hasXSAVE.Offset }})
#define CPU_HAS_XSAVEOPT ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.hasXSAVEOPT.Offset }})
{{ with .kernelEntry }}
#define ENTRY_SCRATCH0 {{ .scratch0.Offset }}
#define ENTRY_STACK_TOP {{ .stackTop.Offset }}
#define ENTRY_CPU_SELF {{ .cpuSelf.Offset }}
#define ENTRY_KERNEL_CR3 {{ .kernelCR3.Offset }}
{{ end }}
// Bits.
#define _RFLAGS_IF {{ ._RFLAGS_IF.Value }}
#define _RFLAGS_IOPL0 {{ ._RFLAGS_IOPL0.Value }}
#define _KERNEL_FLAGS {{ .KernelFlagsSet.Value }}
// Vectors.
#define DivideByZero {{ .DivideByZero.Value }}
#define Debug {{ .Debug.Value }}
#define NMI {{ .NMI.Value }}
#define Breakpoint {{ .Breakpoint.Value }}
#define Overflow {{ .Overflow.Value }}
#define BoundRangeExceeded {{ .BoundRangeExceeded.Value }}
#define InvalidOpcode {{ .InvalidOpcode.Value }}
#define DeviceNotAvailable {{ .DeviceNotAvailable.Value }}
#define DoubleFault {{ .DoubleFault.Value }}
#define CoprocessorSegmentOverrun {{ .CoprocessorSegmentOverrun.Value }}
#define InvalidTSS {{ .InvalidTSS.Value }}
#define SegmentNotPresent {{ .SegmentNotPresent.Value }}
#define StackSegmentFault {{ .StackSegmentFault.Value }}
#define GeneralProtectionFault {{ .GeneralProtectionFault.Value }}
#define PageFault {{ .PageFault.Value }}
#define X87FloatingPointException {{ .X87FloatingPointException.Value }}
#define AlignmentCheck {{ .AlignmentCheck.Value }}
#define MachineCheck {{ .MachineCheck.Value }}
#define SIMDFloatingPointException {{ .SIMDFloatingPointException.Value }}
#define VirtualizationException {{ .VirtualizationException.Value }}
#define SecurityException {{ .SecurityException.Value }}
#define SyscallInt80 {{ .SyscallInt80.Value }}
#define Syscall {{ .Syscall.Value }}
{{ with .import.linux.PtraceRegs }}
#define PTRACE_R15 {{ .R15.Offset }}
#define PTRACE_R14 {{ .R14.Offset }}
#define PTRACE_R13 {{ .R13.Offset }}
#define PTRACE_R12 {{ .R12.Offset }}
#define PTRACE_RBP {{ .Rbp.Offset }}
#define PTRACE_RBX {{ .Rbx.Offset }}
#define PTRACE_R11 {{ .R11.Offset }}
#define PTRACE_R10 {{ .R10.Offset }}
#define PTRACE_R9 {{ .R9.Offset }}
#define PTRACE_R8 {{ .R8.Offset }}
#define PTRACE_RAX {{ .Rax.Offset }}
#define PTRACE_RCX {{ .Rcx.Offset }}
#define PTRACE_RDX {{ .Rdx.Offset }}
#define PTRACE_RSI {{ .Rsi.Offset }}
#define PTRACE_RDI {{ .Rdi.Offset }}
#define PTRACE_ORIGRAX {{ .Orig_rax.Offset }}
#define PTRACE_RIP {{ .Rip.Offset }}
#define PTRACE_CS {{ .Cs.Offset }}
#define PTRACE_FLAGS {{ .Eflags.Offset }}
#define PTRACE_RSP {{ .Rsp.Offset }}
#define PTRACE_SS {{ .Ss.Offset }}
#define PTRACE_FS_BASE {{ .Fs_base.Offset }}
#define PTRACE_GS_BASE {{ .Gs_base.Offset }}
{{ end }}
// Saves a register set. // Saves a register set.
// //
+92 -3
View File
@@ -15,9 +15,98 @@
#include "funcdata.h" #include "funcdata.h"
#include "textflag.h" #include "textflag.h"
// NB: Offsets are programatically generated (see BUILD). {{ with .CPU }}
// #define CPU_SELF {{ .self.Offset }}
// This file is concatenated with the definitions. #define CPU_REGISTERS {{ .registers.Offset }}
{{ end }}
{{ with .CPUArchState }}
#define CPU_STACK_TOP ({{ .stack.Offset }} + {{ .stack.Size }})
#define CPU_ERROR_CODE {{ .errorCode.Offset }}
#define CPU_ERROR_TYPE {{ .errorType.Offset }}
#define CPU_FAULT_ADDR {{ .faultAddr.Offset }}
#define CPU_FPSTATE_EL0 {{ .el0Fp.Offset }}
#define CPU_TTBR0_KVM {{ .ttbr0Kvm.Offset }}
#define CPU_TTBR0_APP {{ .ttbr0App.Offset }}
#define CPU_VECTOR_CODE {{ .vecCode.Offset }}
#define CPU_APP_ADDR {{ .appAddr.Offset }}
#define CPU_LAZY_VFP {{ .lazyVFP.Offset }}
#define CPU_APP_ASID {{ .appASID.Offset }}
{{ end }}
// Bits.
#define _KERNEL_FLAGS {{ .KernelFlagsSet.Value }}
// Vectors.
#define El1Sync {{ .El1Sync.Value }}
#define El1Irq {{ .El1Irq.Value }}
#define El1Fiq {{ .El1Fiq.Value }}
#define El1Err {{ .El1Err.Value }}
#define El0Sync {{ .El0Sync.Value }}
#define El0Irq {{ .El0Irq.Value }}
#define El0Fiq {{ .El0Fiq.Value }}
#define El0Err {{ .El0Err.Value }}
#define El1SyncDa {{ .El1SyncDa.Value }}
#define El1SyncIa {{ .El1SyncIa.Value }}
#define El1SyncSpPc {{ .El1SyncSpPc.Value }}
#define El1SyncUndef {{ .El1SyncUndef.Value }}
#define El1SyncDbg {{ .El1SyncDbg.Value }}
#define El1SyncInv {{ .El1SyncInv.Value }}
#define El0SyncSVC {{ .El0SyncSVC.Value }}
#define El0SyncDa {{ .El0SyncDa.Value }}
#define El0SyncIa {{ .El0SyncIa.Value }}
#define El0SyncFpsimdAcc {{ .El0SyncFpsimdAcc.Value }}
#define El0SyncSveAcc {{ .El0SyncSveAcc.Value }}
#define El0SyncFpsimdExc {{ .El0SyncFpsimdExc.Value }}
#define El0SyncSys {{ .El0SyncSys.Value }}
#define El0SyncSpPc {{ .El0SyncSpPc.Value }}
#define El0SyncUndef {{ .El0SyncUndef.Value }}
#define El0SyncDbg {{ .El0SyncDbg.Value }}
#define El0SyncWfx {{ .El0SyncWfx.Value }}
#define El0SyncInv {{ .El0SyncInv.Value }}
#define El0ErrNMI {{ .El0ErrNMI.Value }}
#define PageFault {{ .PageFault.Value }}
#define Syscall {{ .Syscall.Value }}
#define VirtualizationException {{ .VirtualizationException.Value }}
{{ with .import.linux.PtraceRegs }}
#define PTRACE_R0 ({{ .Regs.Offset }} + 0*8)
#define PTRACE_R1 ({{ .Regs.Offset }} + 1*8)
#define PTRACE_R2 ({{ .Regs.Offset }} + 2*8)
#define PTRACE_R3 ({{ .Regs.Offset }} + 3*8)
#define PTRACE_R4 ({{ .Regs.Offset }} + 4*8)
#define PTRACE_R5 ({{ .Regs.Offset }} + 5*8)
#define PTRACE_R6 ({{ .Regs.Offset }} + 6*8)
#define PTRACE_R7 ({{ .Regs.Offset }} + 7*8)
#define PTRACE_R8 ({{ .Regs.Offset }} + 8*8)
#define PTRACE_R9 ({{ .Regs.Offset }} + 9*8)
#define PTRACE_R10 ({{ .Regs.Offset }} + 10*8)
#define PTRACE_R11 ({{ .Regs.Offset }} + 11*8)
#define PTRACE_R12 ({{ .Regs.Offset }} + 12*8)
#define PTRACE_R13 ({{ .Regs.Offset }} + 13*8)
#define PTRACE_R14 ({{ .Regs.Offset }} + 14*8)
#define PTRACE_R15 ({{ .Regs.Offset }} + 15*8)
#define PTRACE_R16 ({{ .Regs.Offset }} + 16*8)
#define PTRACE_R17 ({{ .Regs.Offset }} + 17*8)
#define PTRACE_R18 ({{ .Regs.Offset }} + 18*8)
#define PTRACE_R19 ({{ .Regs.Offset }} + 19*8)
#define PTRACE_R20 ({{ .Regs.Offset }} + 20*8)
#define PTRACE_R21 ({{ .Regs.Offset }} + 21*8)
#define PTRACE_R22 ({{ .Regs.Offset }} + 22*8)
#define PTRACE_R23 ({{ .Regs.Offset }} + 23*8)
#define PTRACE_R24 ({{ .Regs.Offset }} + 24*8)
#define PTRACE_R25 ({{ .Regs.Offset }} + 25*8)
#define PTRACE_R26 ({{ .Regs.Offset }} + 26*8)
#define PTRACE_R27 ({{ .Regs.Offset }} + 27*8)
#define PTRACE_R28 ({{ .Regs.Offset }} + 28*8)
#define PTRACE_R29 ({{ .Regs.Offset }} + 29*8)
#define PTRACE_R30 ({{ .Regs.Offset }} + 30*8)
#define PTRACE_SP {{ .Sp.Offset }}
#define PTRACE_PC {{ .Pc.Offset }}
#define PTRACE_PSTATE {{ .Pstate.Offset }}
{{ end }}
{{ with .import.arch.Registers }}
#define PTRACE_TLS {{ .TPIDR_EL0.Offset }}
{{ end }}
// Saves a register set. // Saves a register set.
// //
@@ -12,13 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// Binary gen_offsets is a helper for generating offset headers. package ring0
package main
import ( import (
"os" // Used for template generation.
_ "gvisor.dev/gvisor/pkg/abi/linux"
) )
func main() {
Emit(os.Stdout)
}
-41
View File
@@ -1,41 +0,0 @@
load("//tools:defs.bzl", "go_binary")
load("//tools/go_generics:defs.bzl", "go_template_instance")
package(licenses = ["notice"])
go_template_instance(
name = "defs_impl_arm64",
out = "defs_impl_arm64.go",
package = "main",
template = "//pkg/ring0:defs_arm64",
)
go_template_instance(
name = "defs_impl_amd64",
out = "defs_impl_amd64.go",
package = "main",
template = "//pkg/ring0:defs_amd64",
)
go_binary(
name = "gen_offsets",
srcs = [
"defs_impl_amd64.go",
"defs_impl_arm64.go",
"main.go",
],
# Use the libc malloc to avoid any extra dependencies. This is required to
# pass the sentry deps test.
system_malloc = True,
visibility = [
"//pkg/ring0:__pkg__",
"//pkg/sentry/platform/kvm:__pkg__",
],
deps = [
"//pkg/cpuid",
"//pkg/hostarch",
"//pkg/ring0/pagetables",
"//pkg/sentry/arch",
"//pkg/sentry/arch/fpu",
],
)
-104
View File
@@ -1,104 +0,0 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build amd64
// +build amd64
package ring0
import (
"fmt"
"io"
"reflect"
"gvisor.dev/gvisor/pkg/sentry/arch"
)
// Emit prints architecture-specific offsets.
func Emit(w io.Writer) {
fmt.Fprintf(w, "// Automatically generated, do not edit.\n")
c := &CPU{}
fmt.Fprintf(w, "\n// CPU offsets.\n")
fmt.Fprintf(w, "#define CPU_REGISTERS 0x%02x\n", reflect.ValueOf(&c.registers).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_ERROR_CODE 0x%02x\n", reflect.ValueOf(&c.errorCode).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_ERROR_TYPE 0x%02x\n", reflect.ValueOf(&c.errorType).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_ENTRY 0x%02x\n", reflect.ValueOf(&c.kernelEntry).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_HAS_XSAVE 0x%02x\n", reflect.ValueOf(&c.hasXSAVE).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_HAS_XSAVEOPT 0x%02x\n", reflect.ValueOf(&c.hasXSAVEOPT).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_FPU_STATE 0x%02x\n", reflect.ValueOf(&c.floatingPointState).Pointer()-reflect.ValueOf(c).Pointer())
e := &kernelEntry{}
fmt.Fprintf(w, "\n// CPU entry offsets.\n")
fmt.Fprintf(w, "#define ENTRY_SCRATCH0 0x%02x\n", reflect.ValueOf(&e.scratch0).Pointer()-reflect.ValueOf(e).Pointer())
fmt.Fprintf(w, "#define ENTRY_STACK_TOP 0x%02x\n", reflect.ValueOf(&e.stackTop).Pointer()-reflect.ValueOf(e).Pointer())
fmt.Fprintf(w, "#define ENTRY_CPU_SELF 0x%02x\n", reflect.ValueOf(&e.cpuSelf).Pointer()-reflect.ValueOf(e).Pointer())
fmt.Fprintf(w, "#define ENTRY_KERNEL_CR3 0x%02x\n", reflect.ValueOf(&e.kernelCR3).Pointer()-reflect.ValueOf(e).Pointer())
fmt.Fprintf(w, "\n// Bits.\n")
fmt.Fprintf(w, "#define _RFLAGS_IF 0x%02x\n", _RFLAGS_IF)
fmt.Fprintf(w, "#define _RFLAGS_IOPL0 0x%02x\n", _RFLAGS_IOPL0)
fmt.Fprintf(w, "#define _KERNEL_FLAGS 0x%02x\n", KernelFlagsSet)
fmt.Fprintf(w, "\n// Vectors.\n")
fmt.Fprintf(w, "#define DivideByZero 0x%02x\n", DivideByZero)
fmt.Fprintf(w, "#define Debug 0x%02x\n", Debug)
fmt.Fprintf(w, "#define NMI 0x%02x\n", NMI)
fmt.Fprintf(w, "#define Breakpoint 0x%02x\n", Breakpoint)
fmt.Fprintf(w, "#define Overflow 0x%02x\n", Overflow)
fmt.Fprintf(w, "#define BoundRangeExceeded 0x%02x\n", BoundRangeExceeded)
fmt.Fprintf(w, "#define InvalidOpcode 0x%02x\n", InvalidOpcode)
fmt.Fprintf(w, "#define DeviceNotAvailable 0x%02x\n", DeviceNotAvailable)
fmt.Fprintf(w, "#define DoubleFault 0x%02x\n", DoubleFault)
fmt.Fprintf(w, "#define CoprocessorSegmentOverrun 0x%02x\n", CoprocessorSegmentOverrun)
fmt.Fprintf(w, "#define InvalidTSS 0x%02x\n", InvalidTSS)
fmt.Fprintf(w, "#define SegmentNotPresent 0x%02x\n", SegmentNotPresent)
fmt.Fprintf(w, "#define StackSegmentFault 0x%02x\n", StackSegmentFault)
fmt.Fprintf(w, "#define GeneralProtectionFault 0x%02x\n", GeneralProtectionFault)
fmt.Fprintf(w, "#define PageFault 0x%02x\n", PageFault)
fmt.Fprintf(w, "#define X87FloatingPointException 0x%02x\n", X87FloatingPointException)
fmt.Fprintf(w, "#define AlignmentCheck 0x%02x\n", AlignmentCheck)
fmt.Fprintf(w, "#define MachineCheck 0x%02x\n", MachineCheck)
fmt.Fprintf(w, "#define SIMDFloatingPointException 0x%02x\n", SIMDFloatingPointException)
fmt.Fprintf(w, "#define VirtualizationException 0x%02x\n", VirtualizationException)
fmt.Fprintf(w, "#define SecurityException 0x%02x\n", SecurityException)
fmt.Fprintf(w, "#define SyscallInt80 0x%02x\n", SyscallInt80)
fmt.Fprintf(w, "#define Syscall 0x%02x\n", Syscall)
p := &arch.Registers{}
fmt.Fprintf(w, "\n// Ptrace registers.\n")
fmt.Fprintf(w, "#define PTRACE_R15 0x%02x\n", reflect.ValueOf(&p.R15).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R14 0x%02x\n", reflect.ValueOf(&p.R14).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R13 0x%02x\n", reflect.ValueOf(&p.R13).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R12 0x%02x\n", reflect.ValueOf(&p.R12).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RBP 0x%02x\n", reflect.ValueOf(&p.Rbp).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RBX 0x%02x\n", reflect.ValueOf(&p.Rbx).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R11 0x%02x\n", reflect.ValueOf(&p.R11).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R10 0x%02x\n", reflect.ValueOf(&p.R10).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R9 0x%02x\n", reflect.ValueOf(&p.R9).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R8 0x%02x\n", reflect.ValueOf(&p.R8).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RAX 0x%02x\n", reflect.ValueOf(&p.Rax).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RCX 0x%02x\n", reflect.ValueOf(&p.Rcx).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RDX 0x%02x\n", reflect.ValueOf(&p.Rdx).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RSI 0x%02x\n", reflect.ValueOf(&p.Rsi).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RDI 0x%02x\n", reflect.ValueOf(&p.Rdi).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_ORIGRAX 0x%02x\n", reflect.ValueOf(&p.Orig_rax).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RIP 0x%02x\n", reflect.ValueOf(&p.Rip).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_CS 0x%02x\n", reflect.ValueOf(&p.Cs).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_FLAGS 0x%02x\n", reflect.ValueOf(&p.Eflags).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_RSP 0x%02x\n", reflect.ValueOf(&p.Rsp).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_SS 0x%02x\n", reflect.ValueOf(&p.Ss).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_FS_BASE 0x%02x\n", reflect.ValueOf(&p.Fs_base).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_GS_BASE 0x%02x\n", reflect.ValueOf(&p.Gs_base).Pointer()-reflect.ValueOf(p).Pointer())
}
-126
View File
@@ -1,126 +0,0 @@
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build arm64
// +build arm64
package ring0
import (
"fmt"
"io"
"reflect"
"gvisor.dev/gvisor/pkg/sentry/arch"
)
// Emit prints architecture-specific offsets.
func Emit(w io.Writer) {
fmt.Fprintf(w, "// Automatically generated, do not edit.\n")
c := &CPU{}
fmt.Fprintf(w, "\n// CPU offsets.\n")
fmt.Fprintf(w, "#define CPU_SELF 0x%02x\n", reflect.ValueOf(&c.self).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_REGISTERS 0x%02x\n", reflect.ValueOf(&c.registers).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_STACK_TOP 0x%02x\n", reflect.ValueOf(&c.stack[0]).Pointer()-reflect.ValueOf(c).Pointer()+uintptr(len(c.stack)))
fmt.Fprintf(w, "#define CPU_ERROR_CODE 0x%02x\n", reflect.ValueOf(&c.errorCode).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_ERROR_TYPE 0x%02x\n", reflect.ValueOf(&c.errorType).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_FAULT_ADDR 0x%02x\n", reflect.ValueOf(&c.faultAddr).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_FPSTATE_EL0 0x%02x\n", reflect.ValueOf(&c.el0Fp).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_TTBR0_KVM 0x%02x\n", reflect.ValueOf(&c.ttbr0Kvm).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_TTBR0_APP 0x%02x\n", reflect.ValueOf(&c.ttbr0App).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_VECTOR_CODE 0x%02x\n", reflect.ValueOf(&c.vecCode).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_APP_ADDR 0x%02x\n", reflect.ValueOf(&c.appAddr).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_LAZY_VFP 0x%02x\n", reflect.ValueOf(&c.lazyVFP).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "#define CPU_APP_ASID 0x%02x\n", reflect.ValueOf(&c.appASID).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "\n// Bits.\n")
fmt.Fprintf(w, "#define _KERNEL_FLAGS 0x%02x\n", KernelFlagsSet)
fmt.Fprintf(w, "\n// Vectors.\n")
fmt.Fprintf(w, "#define El1Sync 0x%02x\n", El1Sync)
fmt.Fprintf(w, "#define El1Irq 0x%02x\n", El1Irq)
fmt.Fprintf(w, "#define El1Fiq 0x%02x\n", El1Fiq)
fmt.Fprintf(w, "#define El1Err 0x%02x\n", El1Err)
fmt.Fprintf(w, "#define El0Sync 0x%02x\n", El0Sync)
fmt.Fprintf(w, "#define El0Irq 0x%02x\n", El0Irq)
fmt.Fprintf(w, "#define El0Fiq 0x%02x\n", El0Fiq)
fmt.Fprintf(w, "#define El0Err 0x%02x\n", El0Err)
fmt.Fprintf(w, "#define El1SyncDa 0x%02x\n", El1SyncDa)
fmt.Fprintf(w, "#define El1SyncIa 0x%02x\n", El1SyncIa)
fmt.Fprintf(w, "#define El1SyncSpPc 0x%02x\n", El1SyncSpPc)
fmt.Fprintf(w, "#define El1SyncUndef 0x%02x\n", El1SyncUndef)
fmt.Fprintf(w, "#define El1SyncDbg 0x%02x\n", El1SyncDbg)
fmt.Fprintf(w, "#define El1SyncInv 0x%02x\n", El1SyncInv)
fmt.Fprintf(w, "#define El0SyncSVC 0x%02x\n", El0SyncSVC)
fmt.Fprintf(w, "#define El0SyncDa 0x%02x\n", El0SyncDa)
fmt.Fprintf(w, "#define El0SyncIa 0x%02x\n", El0SyncIa)
fmt.Fprintf(w, "#define El0SyncFpsimdAcc 0x%02x\n", El0SyncFpsimdAcc)
fmt.Fprintf(w, "#define El0SyncSveAcc 0x%02x\n", El0SyncSveAcc)
fmt.Fprintf(w, "#define El0SyncFpsimdExc 0x%02x\n", El0SyncFpsimdExc)
fmt.Fprintf(w, "#define El0SyncSys 0x%02x\n", El0SyncSys)
fmt.Fprintf(w, "#define El0SyncSpPc 0x%02x\n", El0SyncSpPc)
fmt.Fprintf(w, "#define El0SyncUndef 0x%02x\n", El0SyncUndef)
fmt.Fprintf(w, "#define El0SyncDbg 0x%02x\n", El0SyncDbg)
fmt.Fprintf(w, "#define El0SyncWfx 0x%02x\n", El0SyncWfx)
fmt.Fprintf(w, "#define El0SyncInv 0x%02x\n", El0SyncInv)
fmt.Fprintf(w, "#define El0ErrNMI 0x%02x\n", El0ErrNMI)
fmt.Fprintf(w, "#define PageFault 0x%02x\n", PageFault)
fmt.Fprintf(w, "#define Syscall 0x%02x\n", Syscall)
fmt.Fprintf(w, "#define VirtualizationException 0x%02x\n", VirtualizationException)
p := &arch.Registers{}
fmt.Fprintf(w, "\n// Ptrace registers.\n")
fmt.Fprintf(w, "#define PTRACE_R0 0x%02x\n", reflect.ValueOf(&p.Regs[0]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R1 0x%02x\n", reflect.ValueOf(&p.Regs[1]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R2 0x%02x\n", reflect.ValueOf(&p.Regs[2]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R3 0x%02x\n", reflect.ValueOf(&p.Regs[3]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R4 0x%02x\n", reflect.ValueOf(&p.Regs[4]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R5 0x%02x\n", reflect.ValueOf(&p.Regs[5]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R6 0x%02x\n", reflect.ValueOf(&p.Regs[6]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R7 0x%02x\n", reflect.ValueOf(&p.Regs[7]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R8 0x%02x\n", reflect.ValueOf(&p.Regs[8]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R9 0x%02x\n", reflect.ValueOf(&p.Regs[9]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R10 0x%02x\n", reflect.ValueOf(&p.Regs[10]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R11 0x%02x\n", reflect.ValueOf(&p.Regs[11]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R12 0x%02x\n", reflect.ValueOf(&p.Regs[12]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R13 0x%02x\n", reflect.ValueOf(&p.Regs[13]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R14 0x%02x\n", reflect.ValueOf(&p.Regs[14]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R15 0x%02x\n", reflect.ValueOf(&p.Regs[15]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R16 0x%02x\n", reflect.ValueOf(&p.Regs[16]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R17 0x%02x\n", reflect.ValueOf(&p.Regs[17]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R18 0x%02x\n", reflect.ValueOf(&p.Regs[18]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R19 0x%02x\n", reflect.ValueOf(&p.Regs[19]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R20 0x%02x\n", reflect.ValueOf(&p.Regs[20]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R21 0x%02x\n", reflect.ValueOf(&p.Regs[21]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R22 0x%02x\n", reflect.ValueOf(&p.Regs[22]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R23 0x%02x\n", reflect.ValueOf(&p.Regs[23]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R24 0x%02x\n", reflect.ValueOf(&p.Regs[24]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R25 0x%02x\n", reflect.ValueOf(&p.Regs[25]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R26 0x%02x\n", reflect.ValueOf(&p.Regs[26]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R27 0x%02x\n", reflect.ValueOf(&p.Regs[27]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R28 0x%02x\n", reflect.ValueOf(&p.Regs[28]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R29 0x%02x\n", reflect.ValueOf(&p.Regs[29]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_R30 0x%02x\n", reflect.ValueOf(&p.Regs[30]).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_SP 0x%02x\n", reflect.ValueOf(&p.Sp).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_PC 0x%02x\n", reflect.ValueOf(&p.Pc).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_PSTATE 0x%02x\n", reflect.ValueOf(&p.Pstate).Pointer()-reflect.ValueOf(p).Pointer())
fmt.Fprintf(w, "#define PTRACE_TLS 0x%02x\n", reflect.ValueOf(&p.TPIDR_EL0).Pointer()-reflect.ValueOf(p).Pointer())
}
+34 -11
View File
@@ -1,5 +1,6 @@
load("//tools:defs.bzl", "go_library", "go_test") load("//tools:defs.bzl", "arch_genrule", "go_library", "go_test", "select_arch")
load("//tools/go_generics:defs.bzl", "go_template_instance") load("//tools/go_generics:defs.bzl", "go_template_instance")
load("//tools/nogo:defs.bzl", "nogo_facts")
package(licenses = ["notice"]) package(licenses = ["notice"])
@@ -14,6 +15,37 @@ go_template_instance(
}, },
) )
nogo_facts(
name = "bluepill_impl",
srcs = [
"//pkg/ring0:aarch64.go",
"//pkg/ring0:defs.go",
"//pkg/ring0:defs_amd64.go",
"//pkg/ring0:defs_arm64.go",
"//pkg/ring0:entry_template.go",
"//pkg/ring0:x86.go",
],
output = "bluepill_impl.s",
template = select_arch(
amd64 = "bluepill_amd64.s",
arm64 = "bluepill_arm64.s",
),
deps = [
"//pkg/abi/linux",
"//pkg/cpuid",
"//pkg/hostarch",
"//pkg/ring0/pagetables",
"//pkg/sentry/arch",
"//pkg/sentry/arch/fpu",
],
)
arch_genrule(
name = "bluepill_impl_arch",
src = ":bluepill_impl",
template = "bluepill_impl_%s.s",
)
go_library( go_library(
name = "kvm", name = "kvm",
srcs = [ srcs = [
@@ -26,10 +58,8 @@ go_library(
"bluepill_amd64.go", "bluepill_amd64.go",
"bluepill_amd64_unsafe.go", "bluepill_amd64_unsafe.go",
"bluepill_arm64.go", "bluepill_arm64.go",
"bluepill_arm64.s",
"bluepill_arm64_unsafe.go", "bluepill_arm64_unsafe.go",
"bluepill_fault.go", "bluepill_fault.go",
"bluepill_impl_amd64.s",
"bluepill_unsafe.go", "bluepill_unsafe.go",
"context.go", "context.go",
"filters_amd64.go", "filters_amd64.go",
@@ -51,6 +81,7 @@ go_library(
"physical_map_amd64.go", "physical_map_amd64.go",
"physical_map_arm64.go", "physical_map_arm64.go",
"virtual_map.go", "virtual_map.go",
":bluepill_impl_arch",
], ],
visibility = ["//pkg/sentry:internal"], visibility = ["//pkg/sentry:internal"],
deps = [ deps = [
@@ -113,11 +144,3 @@ go_test(
"@org_golang_x_sys//unix:go_default_library", "@org_golang_x_sys//unix:go_default_library",
], ],
) )
genrule(
name = "bluepill_impl_amd64",
srcs = ["bluepill_amd64.s"],
outs = ["bluepill_impl_amd64.s"],
cmd = "(echo -e '// build +amd64\\n' && $(location //pkg/ring0/gen_offsets) && cat $(SRCS)) > $@",
tools = ["//pkg/ring0/gen_offsets"],
)
+6
View File
@@ -19,6 +19,11 @@
// This is guaranteed to be zero. // This is guaranteed to be zero.
#define VCPU_CPU 0x0 #define VCPU_CPU 0x0
// ENTRY_CPU_SELF is the location of the CPU in the entry struct.
//
// This is sourced from ring0.
#define ENTRY_CPU_SELF {{ .kernelEntry.cpuSelf.Offset }}
// Context offsets. // Context offsets.
// //
// Only limited use of the context is done in the assembly stub below, most is // Only limited use of the context is done in the assembly stub below, most is
@@ -32,6 +37,7 @@
// This is checked as the source of the fault. // This is checked as the source of the fault.
#define CLI $0xfa #define CLI $0xfa
// System call definitions.
#define SYS_MMAP 9 #define SYS_MMAP 9
// See bluepill.go. // See bluepill.go.
+2
View File
@@ -30,9 +30,11 @@ var (
Bool = flag.Bool Bool = flag.Bool
CommandLine = flag.CommandLine CommandLine = flag.CommandLine
Int = flag.Int Int = flag.Int
Int64 = flag.Int64
NewFlagSet = flag.NewFlagSet NewFlagSet = flag.NewFlagSet
Parse = flag.Parse Parse = flag.Parse
String = flag.String String = flag.String
StringVar = flag.StringVar
Uint = flag.Uint Uint = flag.Uint
Var = flag.Var Var = flag.Var
) )
-15
View File
@@ -1,15 +0,0 @@
diff --git a/language/go/generate.go b/language/go/generate.go
index 2892948..feb4ad6 100644
--- a/language/go/generate.go
+++ b/language/go/generate.go
@@ -691,6 +691,10 @@ func (g *generator) setImportAttrs(r *rule.Rule, importPath string) {
}
func (g *generator) commonVisibility(importPath string) []string {
+ if importPath == "golang.org/x/tools/go/analysis/internal/facts" {
+ // Imported by nogo main. We add a visibility exception.
+ return []string{"//visibility:public"}
+ }
// If the Bazel package name (rel) contains "internal", add visibility for
// subpackages of the parent.
// If the import path contains "internal" but rel does not, this is
+22 -41
View File
@@ -33,6 +33,28 @@ def select_system(linux = ["__linux__"], darwin = [], **kwargs):
"//conditions:default": linux, "//conditions:default": linux,
}) })
arch_config = [
"//command_line_option:cpu",
"//command_line_option:crosstool_top",
"//command_line_option:platforms",
]
def arm64_config(settings, attr):
return {
"//command_line_option:cpu": "aarch64",
"//command_line_option:crosstool_top": "@crosstool//:toolchains",
"//command_line_option:platforms": "@io_bazel_rules_go//go/toolchain:linux_arm64",
}
def amd64_config(settings, attr):
return {
"//command_line_option:cpu": "k8",
"//command_line_option:crosstool_top": "@crosstool//:toolchains",
"//command_line_option:platforms": "@io_bazel_rules_go//go/toolchain:linux_amd64",
}
transition_allowlist = "@bazel_tools//tools/allowlists/function_transition_allowlist"
def default_installer(): def default_installer():
return None return None
@@ -41,44 +63,3 @@ def default_net_util():
def coreutil(): def coreutil():
return [] # Nothing needed. return [] # Nothing needed.
def select_native_vs_cross(native = [], amd64 = [], arm64 = [], cross = []):
values = {
"//tools/bazeldefs:linux_arm64_cross": arm64 + cross,
"//tools/bazeldefs:linux_amd64_cross": amd64 + cross,
"//conditions:default": native,
}
return select(values)
def arch_genrule(name, srcs, outs, cmd, tools):
"""Runs a gen command on the target architecture.
If the target architecture isn't match the host architecture, it will build
a command for the target architecture and run it via qemu.
The native genrule runs the command on the host architecture.
Args:
name: name of generated target.
srcs: A list of inputs for this rule.
cmd: The command to run. It has to contain " QEMU " before executed binaries.
outs: A list of files generated by this rule.
tools: A list of tool dependencies for this rule.
"""
qemu_arm64 = "qemu-aarch64-static"
qemu_amd64 = "qemu-x86_64-static"
srcs = select_native_vs_cross(
cross = srcs + tools,
native = srcs,
)
tools = select_native_vs_cross(
cross = [],
native = tools,
)
cmd = select_native_vs_cross(
arm64 = cmd.replace("QEMU", qemu_arm64),
amd64 = cmd.replace("QEMU", qemu_amd64),
native = cmd.replace("QEMU", ""),
cross = "",
)
native.genrule(name = name, srcs = srcs, outs = outs, cmd = cmd, tools = tools)
+2 -6
View File
@@ -135,17 +135,13 @@ def go_context(ctx, goos = None, goarch = None, std = False):
go_ctx = _go_context(ctx) go_ctx = _go_context(ctx)
if goos == None: if goos == None:
goos = go_ctx.sdk.goos goos = go_ctx.sdk.goos
elif goos != go_ctx.sdk.goos:
fail("Internal GOOS (%s) doesn't match GoSdk GOOS (%s)." % (goos, go_ctx.sdk.goos))
if goarch == None: if goarch == None:
goarch = go_ctx.sdk.goarch goarch = go_ctx.sdk.goarch
elif goarch != go_ctx.sdk.goarch:
fail("Internal GOARCH (%s) doesn't match GoSdk GOARCH (%s)." % (goarch, go_ctx.sdk.goarch))
return struct( return struct(
env = go_ctx.env, env = go_ctx.env,
go = go_ctx.go, go = go_ctx.go,
goarch = go_ctx.sdk.goarch, goarch = goarch,
goos = go_ctx.sdk.goos, goos = goos,
gotags = go_ctx.tags, gotags = go_ctx.tags,
nogo_args = [], nogo_args = [],
runfiles = depset([go_ctx.go] + go_ctx.sdk.srcs + go_ctx.sdk.tools + go_ctx.stdlib.libs), runfiles = depset([go_ctx.go] + go_ctx.sdk.srcs + go_ctx.sdk.tools + go_ctx.stdlib.libs),
+1 -1
View File
@@ -8,7 +8,7 @@ go_library(
nogo = False, nogo = False,
visibility = ["//tools/nogo:__subpackages__"], visibility = ["//tools/nogo:__subpackages__"],
deps = [ deps = [
"//tools/nogo/objdump", "//tools/nogo/flags",
"@org_golang_x_tools//go/analysis:go_default_library", "@org_golang_x_tools//go/analysis:go_default_library",
"@org_golang_x_tools//go/analysis/passes/buildssa:go_default_library", "@org_golang_x_tools//go/analysis/passes/buildssa:go_default_library",
"@org_golang_x_tools//go/ssa:go_default_library", "@org_golang_x_tools//go/ssa:go_default_library",
+151 -115
View File
@@ -66,14 +66,17 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"io" "io"
"io/ioutil"
"log" "log"
"os"
"os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa" "golang.org/x/tools/go/analysis/passes/buildssa"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"gvisor.dev/gvisor/tools/nogo/objdump" "gvisor.dev/gvisor/tools/nogo/flags"
) )
const ( const (
@@ -177,21 +180,30 @@ type packageEscapeFacts struct {
// AFact implements analysis.Fact.AFact. // AFact implements analysis.Fact.AFact.
func (*packageEscapeFacts) AFact() {} func (*packageEscapeFacts) AFact() {}
// Analyzer includes specific results. // objdumpAnalyzer accepts the objdump parameter.
var Analyzer = &analysis.Analyzer{ type objdumpAnalyzer struct {
Name: "checkescape", analysis.Analyzer
Doc: "escape analysis checks based on +checkescape annotations",
Run: runSelectEscapes,
Requires: []*analysis.Analyzer{buildssa.Analyzer},
FactTypes: []analysis.Fact{(*packageEscapeFacts)(nil)},
} }
// EscapeAnalyzer includes all local escape results. // Run implements nogo.binaryAnalyzer.Run.
var EscapeAnalyzer = &analysis.Analyzer{ func (ob *objdumpAnalyzer) Run(pass *analysis.Pass, binary io.Reader) (interface{}, error) {
Name: "checkescape", return run(pass, binary)
Doc: "complete local escape analysis results (requires Analyzer facts)", }
Run: runAllEscapes,
Requires: []*analysis.Analyzer{buildssa.Analyzer}, // Legacy implements nogo.analyzer.Legacy.
func (ob *objdumpAnalyzer) Legacy() *analysis.Analyzer {
return &ob.Analyzer
}
// Analyzer includes specific results.
var Analyzer = &objdumpAnalyzer{
Analyzer: analysis.Analyzer{
Name: "checkescape",
Doc: "escape analysis checks based on +checkescape annotations",
Run: nil, // Must be invoked via Run above.
Requires: []*analysis.Analyzer{buildssa.Analyzer},
FactTypes: []analysis.Fact{(*packageEscapeFacts)(nil)},
},
} }
// LinePosition is a low-resolution token.Position. // LinePosition is a low-resolution token.Position.
@@ -356,7 +368,65 @@ func MergeAll(others []Escapes) (es Escapes) {
// //
// Note that the map uses <basename.go>:<line> because that is all that is // Note that the map uses <basename.go>:<line> because that is all that is
// provided in the objdump format. Since this is all local, it is sufficient. // provided in the objdump format. Since this is all local, it is sufficient.
func loadObjdump() (map[string][]string, error) { func loadObjdump(binary io.Reader) (finalResults map[string][]string, finalErr error) {
// Do we have a binary? If it's missing, then the nil will simply be
// plumbed all the way down here.
if binary == nil {
return nil, fmt.Errorf("no binary provided")
}
// Construct & start our command. The 'go tool objdump' command
// requires a seekable input passed on the command line. Therefore, we
// may need to generate a temporary file here.
input, ok := binary.(*os.File)
if ok {
// Ensure that the file is seekable and that the offset is
// zero, since we can't control that.
if offset, err := input.Seek(0, os.SEEK_CUR); err != nil || offset != 0 {
ok = false // Not usable.
}
}
if !ok {
// Copy to a temporary path.
f, err := ioutil.TempFile("", "")
if err != nil {
return nil, fmt.Errorf("unable to create temp file: %w", err)
}
// Ensure the file is deleted.
defer os.Remove(f.Name())
// Populate the file contents.
if _, err := io.Copy(f, binary); err != nil {
return nil, fmt.Errorf("unable to populate temp file: %w", err)
}
// Seek to the beginning.
if _, err := f.Seek(0, os.SEEK_SET); err != nil {
return nil, fmt.Errorf("unable to seek in temp file: %w", err)
}
input = f
}
// Execute go tool objdump ggiven the input.
cmd := exec.Command(flags.Go, "tool", "objdump", input.Name())
cmd.Stderr = os.Stderr
pipeOut, pipeErr := cmd.StdoutPipe()
if pipeErr != nil {
return nil, fmt.Errorf("unable to load objdump: %w", pipeErr)
}
if startErr := cmd.Start(); startErr != nil {
return nil, fmt.Errorf("unable to start objdump: %w", startErr)
}
// Ensure that the command has finished successfully. Note that even if
// we parse the first few lines correctly, and early exit could
// indicate that the dump was incomplete and we could be missed some
// escapes that would have appeared. We need to force failure.
defer func() {
if waitErr := cmd.Wait(); finalErr == nil && waitErr != nil {
// Override the function's return value in this case.
finalErr = fmt.Errorf("error running objdump: %v", waitErr)
}
}()
// Identify calls by address or name. Note that this is also // Identify calls by address or name. Note that this is also
// constructed dynamically below, as we encounted the addresses. // constructed dynamically below, as we encounted the addresses.
// This is because some of the functions (duffzero) may have // This is because some of the functions (duffzero) may have
@@ -389,83 +459,78 @@ func loadObjdump() (map[string][]string, error) {
// Build the map. // Build the map.
nextFunc := "" // For funcsAllowed. nextFunc := "" // For funcsAllowed.
m := make(map[string][]string) m := make(map[string][]string)
if err := objdump.Load(func(origR io.Reader) error { r := bufio.NewReader(pipeOut)
r := bufio.NewReader(origR) NextLine:
NextLine: for {
for { line, err := r.ReadString('\n')
line, err := r.ReadString('\n') if err != nil && err != io.EOF {
if err != nil && err != io.EOF { return nil, err
return err }
fields := strings.Fields(line)
// Is this an "allowed" function definition?
if len(fields) >= 2 && fields[0] == "TEXT" {
nextFunc = strings.TrimSuffix(fields[1], "(SB)")
if _, ok := funcsAllowed[nextFunc]; !ok {
nextFunc = "" // Don't record addresses.
} }
fields := strings.Fields(line) }
if nextFunc != "" && len(fields) > 2 {
// Save the given address (in hex form, as it appears).
addrsAllowed[fields[1]] = struct{}{}
}
// Is this an "allowed" function definition? // We recognize lines corresponding to actual code (not the
if len(fields) >= 2 && fields[0] == "TEXT" { // symbol name or other metadata) and annotate them if they
nextFunc = strings.TrimSuffix(fields[1], "(SB)") // correspond to an explicit CALL instruction. We assume that
if _, ok := funcsAllowed[nextFunc]; !ok { // the lack of a CALL for a given line is evidence that escape
nextFunc = "" // Don't record addresses. // analysis has eliminated an allocation.
} //
// Lines look like this (including the first space):
// gohacks_unsafe.go:33 0xa39 488b442408 MOVQ 0x8(SP), AX
if len(fields) >= 5 && line[0] == ' ' {
if !strings.Contains(fields[3], "CALL") {
continue
} }
if nextFunc != "" && len(fields) > 2 { site := fields[0]
// Save the given address (in hex form, as it appears). target := strings.TrimSuffix(fields[4], "(SB)")
addrsAllowed[fields[1]] = struct{}{}
// Ignore strings containing allowed functions.
if _, ok := funcsAllowed[target]; ok {
continue
} }
if _, ok := addrsAllowed[target]; ok {
// We recognize lines corresponding to actual code (not the continue
// symbol name or other metadata) and annotate them if they }
// correspond to an explicit CALL instruction. We assume that if len(fields) > 5 {
// the lack of a CALL for a given line is evidence that escape // This may be a future relocation. Some
// analysis has eliminated an allocation. // objdump versions describe this differently.
// // If it contains any of the functions allowed
// Lines look like this (including the first space): // above as a string, we let it go.
// gohacks_unsafe.go:33 0xa39 488b442408 MOVQ 0x8(SP), AX softTarget := strings.Join(fields[5:], " ")
if len(fields) >= 5 && line[0] == ' ' { for name := range funcsAllowed {
if !strings.Contains(fields[3], "CALL") { if strings.Contains(softTarget, name) {
continue
}
site := fields[0]
target := strings.TrimSuffix(fields[4], "(SB)")
// Ignore strings containing allowed functions.
if _, ok := funcsAllowed[target]; ok {
continue
}
if _, ok := addrsAllowed[target]; ok {
continue
}
if len(fields) > 5 {
// This may be a future relocation. Some
// objdump versions describe this differently.
// If it contains any of the functions allowed
// above as a string, we let it go.
softTarget := strings.Join(fields[5:], " ")
for name := range funcsAllowed {
if strings.Contains(softTarget, name) {
continue NextLine
}
}
}
// Does this exist already?
existing, ok := m[site]
if !ok {
existing = make([]string, 0, 1)
}
for _, other := range existing {
if target == other {
continue NextLine continue NextLine
} }
} }
existing = append(existing, target)
m[site] = existing // Update.
} }
if err == io.EOF {
break // Does this exist already?
existing, ok := m[site]
if !ok {
existing = make([]string, 0, 1)
} }
for _, other := range existing {
if target == other {
continue NextLine
}
}
existing = append(existing, target)
m[site] = existing // Update.
}
if err == io.EOF {
break
} }
return nil
}); err != nil {
return nil, err
} }
// Zap any accidental false positives. // Zap any accidental false positives.
@@ -489,16 +554,6 @@ type poser interface {
Pos() token.Pos Pos() token.Pos
} }
// runSelectEscapes runs with only select escapes.
func runSelectEscapes(pass *analysis.Pass) (interface{}, error) {
return run(pass, false)
}
// runAllEscapes runs with all escapes included.
func runAllEscapes(pass *analysis.Pass) (interface{}, error) {
return run(pass, true)
}
// findReasons extracts reasons from the function. // findReasons extracts reasons from the function.
func findReasons(pass *analysis.Pass, fdecl *ast.FuncDecl) ([]EscapeReason, bool, map[EscapeReason]bool) { func findReasons(pass *analysis.Pass, fdecl *ast.FuncDecl) ([]EscapeReason, bool, map[EscapeReason]bool) {
// Is there a comment? // Is there a comment?
@@ -575,8 +630,8 @@ func findReasons(pass *analysis.Pass, fdecl *ast.FuncDecl) ([]EscapeReason, bool
} }
// run performs the analysis. // run performs the analysis.
func run(pass *analysis.Pass, localEscapes bool) (interface{}, error) { func run(pass *analysis.Pass, binary io.Reader) (interface{}, error) {
calls, callsErr := loadObjdump() calls, callsErr := loadObjdump(binary)
if callsErr != nil { if callsErr != nil {
// Note that if this analysis fails, then we don't actually // Note that if this analysis fails, then we don't actually
// fail the analyzer itself. We simply report every possible // fail the analyzer itself. We simply report every possible
@@ -794,15 +849,6 @@ func run(pass *analysis.Pass, localEscapes bool) (interface{}, error) {
loadFunc(fn) loadFunc(fn)
} }
if !localEscapes {
// Export all findings for future packages. We only do this in
// non-local escapes mode, and expect to run this analysis
// after the SelectAnalysis.
pass.ExportPackageFact(&packageEscapeFacts{
Funcs: mergedEscapes,
})
}
// Scan all functions for violations. // Scan all functions for violations.
for _, f := range pass.Files { for _, f := range pass.Files {
// Scan all declarations. // Scan all declarations.
@@ -812,18 +858,8 @@ func run(pass *analysis.Pass, localEscapes bool) (interface{}, error) {
if !ok { if !ok {
continue continue
} }
var ( // Find all declared reasons.
reasons []EscapeReason reasons, local, testReasons := findReasons(pass, fdecl)
local bool
testReasons map[EscapeReason]bool
)
if localEscapes {
// Find all hard escapes.
reasons = hardReasons
} else {
// Find all declared reasons.
reasons, local, testReasons = findReasons(pass, fdecl)
}
// Scan for matches. // Scan for matches.
fn := pass.TypesInfo.Defs[fdecl.Name].(*types.Func) fn := pass.TypesInfo.Defs[fdecl.Name].(*types.Func)
+11
View File
@@ -0,0 +1,11 @@
load("//tools:defs.bzl", "go_library")
package(licenses = ["notice"])
go_library(
name = "checkinfo",
srcs = ["checkinfo.go"],
nogo = False,
visibility = ["//tools/nogo:__subpackages__"],
deps = ["@org_golang_x_tools//go/analysis:go_default_library"],
)

Some files were not shown because too many files have changed in this diff Show More