mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
3d578afc8d
commit
0e492a2b5e
@@ -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(
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
@@ -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())
|
|
||||||
}
|
|
||||||
@@ -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())
|
|
||||||
}
|
|
||||||
@@ -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"],
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
@@ -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)
|
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user