From 845fb007ded37d9f10292e6e04dc774e4824796c Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Fri, 27 Jan 2023 10:35:45 -0800 Subject: [PATCH] Add constants to package-level fact Unexported constants can end up unaddressable in objectpath and thus their object facts get lost on fact import. Work around this by adding a package-level fact which is a map of all constants to their value. Remove the Value facts because it is confusing to have two ways to access the same thing (especially when one only works sometimes). PiperOrigin-RevId: 505153453 --- pkg/ring0/entry_amd64.s | 52 +++++++++++++++--------------- pkg/ring0/entry_arm64.s | 62 ++++++++++++++++++------------------ tools/checkinfo/checkinfo.go | 49 +++++++++++++++++----------- tools/nogo/facts/facts.go | 19 ++++++++++- 4 files changed, 106 insertions(+), 76 deletions(-) diff --git a/pkg/ring0/entry_amd64.s b/pkg/ring0/entry_amd64.s index 775a46900..f30f48de6 100644 --- a/pkg/ring0/entry_amd64.s +++ b/pkg/ring0/entry_amd64.s @@ -34,34 +34,34 @@ {{ end }} // Bits. -#define _RFLAGS_IF {{ ._RFLAGS_IF.Value }} -#define _RFLAGS_IOPL0 {{ ._RFLAGS_IOPL0.Value }} -#define _KERNEL_FLAGS {{ .KernelFlagsSet.Value }} +#define _RFLAGS_IF {{ .Constants._RFLAGS_IF }} +#define _RFLAGS_IOPL0 {{ .Constants._RFLAGS_IOPL0 }} +#define _KERNEL_FLAGS {{ .Constants.KernelFlagsSet }} // 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 }} +#define DivideByZero {{ .Constants.DivideByZero }} +#define Debug {{ .Constants.Debug }} +#define NMI {{ .Constants.NMI }} +#define Breakpoint {{ .Constants.Breakpoint }} +#define Overflow {{ .Constants.Overflow }} +#define BoundRangeExceeded {{ .Constants.BoundRangeExceeded }} +#define InvalidOpcode {{ .Constants.InvalidOpcode }} +#define DeviceNotAvailable {{ .Constants.DeviceNotAvailable }} +#define DoubleFault {{ .Constants.DoubleFault }} +#define CoprocessorSegmentOverrun {{ .Constants.CoprocessorSegmentOverrun }} +#define InvalidTSS {{ .Constants.InvalidTSS }} +#define SegmentNotPresent {{ .Constants.SegmentNotPresent }} +#define StackSegmentFault {{ .Constants.StackSegmentFault }} +#define GeneralProtectionFault {{ .Constants.GeneralProtectionFault }} +#define PageFault {{ .Constants.PageFault }} +#define X87FloatingPointException {{ .Constants.X87FloatingPointException }} +#define AlignmentCheck {{ .Constants.AlignmentCheck }} +#define MachineCheck {{ .Constants.MachineCheck }} +#define SIMDFloatingPointException {{ .Constants.SIMDFloatingPointException }} +#define VirtualizationException {{ .Constants.VirtualizationException }} +#define SecurityException {{ .Constants.SecurityException }} +#define SyscallInt80 {{ .Constants.SyscallInt80 }} +#define Syscall {{ .Constants.Syscall }} {{ with .import.linux.PtraceRegs }} #define PTRACE_R15 {{ .R15.Offset }} diff --git a/pkg/ring0/entry_arm64.s b/pkg/ring0/entry_arm64.s index 8878bcb2a..7373badaa 100644 --- a/pkg/ring0/entry_arm64.s +++ b/pkg/ring0/entry_arm64.s @@ -30,39 +30,39 @@ #define CPU_APP_ASID ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.appASID.Offset }}) // Bits. -#define _KERNEL_FLAGS {{ .KernelFlagsSet.Value }} +#define _KERNEL_FLAGS {{ .Constants.KernelFlagsSet }} // 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 }} +#define El1Sync {{ .Constants.El1Sync }} +#define El1Irq {{ .Constants.El1Irq }} +#define El1Fiq {{ .Constants.El1Fiq }} +#define El1Err {{ .Constants.El1Err }} +#define El0Sync {{ .Constants.El0Sync }} +#define El0Irq {{ .Constants.El0Irq }} +#define El0Fiq {{ .Constants.El0Fiq }} +#define El0Err {{ .Constants.El0Err }} +#define El1SyncDa {{ .Constants.El1SyncDa }} +#define El1SyncIa {{ .Constants.El1SyncIa }} +#define El1SyncSpPc {{ .Constants.El1SyncSpPc }} +#define El1SyncUndef {{ .Constants.El1SyncUndef }} +#define El1SyncDbg {{ .Constants.El1SyncDbg }} +#define El1SyncInv {{ .Constants.El1SyncInv }} +#define El0SyncSVC {{ .Constants.El0SyncSVC }} +#define El0SyncDa {{ .Constants.El0SyncDa }} +#define El0SyncIa {{ .Constants.El0SyncIa }} +#define El0SyncFpsimdAcc {{ .Constants.El0SyncFpsimdAcc }} +#define El0SyncSveAcc {{ .Constants.El0SyncSveAcc }} +#define El0SyncFpsimdExc {{ .Constants.El0SyncFpsimdExc }} +#define El0SyncSys {{ .Constants.El0SyncSys }} +#define El0SyncSpPc {{ .Constants.El0SyncSpPc }} +#define El0SyncUndef {{ .Constants.El0SyncUndef }} +#define El0SyncDbg {{ .Constants.El0SyncDbg }} +#define El0SyncWfx {{ .Constants.El0SyncWfx }} +#define El0SyncInv {{ .Constants.El0SyncInv }} +#define El0ErrNMI {{ .Constants.El0ErrNMI }} +#define PageFault {{ .Constants.PageFault }} +#define Syscall {{ .Constants.Syscall }} +#define VirtualizationException {{ .Constants.VirtualizationException }} {{ with .import.linux.PtraceRegs }} #define PTRACE_R0 ({{ .Regs.Offset }} + 0*8) diff --git a/tools/checkinfo/checkinfo.go b/tools/checkinfo/checkinfo.go index cf9eef571..d1fcffc7a 100644 --- a/tools/checkinfo/checkinfo.go +++ b/tools/checkinfo/checkinfo.go @@ -30,7 +30,7 @@ var Analyzer = &analysis.Analyzer{ (*Align)(nil), (*Offset)(nil), (*Size)(nil), - (*Value)(nil), + (*Constants)(nil), }, } @@ -52,19 +52,24 @@ type Size int64 // AFact implements analysis.Fact.AFact. func (*Size) AFact() {} -// Value is a trivial fact. -type Value string +// Constants contains all constant values. +type Constants map[string]string // AFact implements analysis.Fact.AFact. -func (*Value) AFact() {} +func (*Constants) AFact() {} -func walkObject(pass *analysis.Pass, obj types.Object) { +// pkg holds package-level facts. +type pkg struct { + constants Constants +} + +func (p *pkg) walkObject(pass *analysis.Pass, obj types.Object) { switch x := obj.(type) { case *types.Const: - // Add a special constant value. This is supported for - // constants only, and appears as a "Value" fact. - v := Value(x.Val().ExactString()) - pass.ExportObjectFact(obj, &v) + // Add to the package-global Constants fact. Unexported + // constants can end up as unaddressable via objectpath and + // thus are not accessible in downstream analyzers. + p.constants[x.Name()] = x.Val().ExactString() case *types.PkgName: // Don't walk to other packages. case *types.Var: @@ -95,7 +100,7 @@ func walkObject(pass *analysis.Pass, obj types.Object) { for i := 0; i < structType.NumFields(); i++ { fieldObj := structType.Field(i) fields = append(fields, fieldObj) - walkObject(pass, fieldObj) + p.walkObject(pass, fieldObj) } offsets := pass.TypesSizes.Offsetsof(fields) for i, field := range fields { @@ -110,31 +115,39 @@ func walkObject(pass *analysis.Pass, obj types.Object) { // Recurse to all parameters. sig := x.Type().(*types.Signature) if recv := sig.Recv(); recv != nil { - walkObject(pass, recv) + p.walkObject(pass, recv) } if params := sig.Params(); params != nil { for i := 0; i < params.Len(); i++ { - walkObject(pass, params.At(i)) + p.walkObject(pass, params.At(i)) } } if results := sig.Results(); results != nil { for i := 0; i < results.Len(); i++ { - walkObject(pass, results.At(i)) + p.walkObject(pass, results.At(i)) } } - walkScope(pass, x.Scope()) + p.walkScope(pass, x.Scope()) } } // walkScope recursively resolves a scope. -func walkScope(pass *analysis.Pass, scope *types.Scope) { +func (p *pkg) walkScope(pass *analysis.Pass, scope *types.Scope) { for _, name := range scope.Names() { - walkObject(pass, scope.Lookup(name)) + p.walkObject(pass, scope.Lookup(name)) } } func run(pass *analysis.Pass) (any, error) { - // Export all facts. - walkScope(pass, pass.Pkg.Scope()) + p := &pkg{ + constants: make(Constants), + } + + // Export all object facts and accumulate all package facts. + p.walkScope(pass, pass.Pkg.Scope()) + + // Export package facts. + pass.ExportPackageFact(&p.constants) + return nil, nil } diff --git a/tools/nogo/facts/facts.go b/tools/nogo/facts/facts.go index 2578431d5..14938d431 100644 --- a/tools/nogo/facts/facts.go +++ b/tools/nogo/facts/facts.go @@ -362,6 +362,21 @@ func (r Resolved) walkScope(parents []string, scope *types.Scope, facts *Package } } +// walkPackage adds all package facts. +func (r Resolved) walkPackage(parents []string, facts *Package, allFactNames map[reflect.Type]string) { + for _, fact := range facts.Objects[nil] { + v := reflect.ValueOf(fact) + typeName, ok := allFactNames[v.Type()] + if !ok { + continue + } + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + r.addRecursively(append(parents, typeName), v.Interface()) + } +} + // Resolve resolves all object facts. func Resolve(pkg *types.Package, localFacts *Package, allFacts *Bundle, allFactNames map[reflect.Type]string) (Resolved, error) { // Populate the tree. Allocating this slice up front prevents @@ -369,6 +384,7 @@ func Resolve(pkg *types.Package, localFacts *Package, allFacts *Bundle, allFactN // without allocating a new backing array. r := make(Resolved) names := make([]string, 0, 64) + r.walkPackage(names, localFacts, allFactNames) r.walkScope(names, pkg.Scope(), localFacts, allFactNames) for _, importPkg := range pkg.Imports() { importFacts, err := allFacts.Package(importPkg) @@ -376,8 +392,9 @@ func Resolve(pkg *types.Package, localFacts *Package, allFacts *Bundle, allFactN return nil, err } if importFacts == nil { - continue + continue // Nothing to render. } + r.walkPackage(append(names, "import", importPkg.Name()), importFacts, allFactNames) r.walkScope(append(names, "import", importPkg.Name()), importPkg.Scope(), importFacts, allFactNames) } return r, nil