syzkaller/sys/align.go
Dmitry Vyukov 959ec07095 sys: always use pointers to types
Currently we store most types by value in sys.Type.
This is somewhat counter-intuitive for C++ programmers,
because one can't easily update the type object.
Store pointers to type objects for all types.
It also makes it easier to update types, e.g. adding paddings.
2016-11-11 14:25:13 -08:00

81 lines
1.6 KiB
Go

// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package sys
func initAlign() {
var rec func(t Type)
rec = func(t Type) {
switch t1 := t.(type) {
case *PtrType:
rec(t1.Type)
case *ArrayType:
rec(t1.Type)
case *StructType:
if !t1.padded {
t1.padded = true
for _, f := range t1.Fields {
rec(f)
}
addAlignment(t1)
}
case *UnionType:
for _, opt := range t1.Options {
rec(opt)
}
}
}
for _, s := range Structs {
rec(s)
}
}
func addAlignment(t *StructType) {
if t.packed {
return
}
var fields []Type
var off, align uintptr
varLen := false
for i, f := range t.Fields {
a := f.Align()
if align < a {
align = a
}
if off%a != 0 {
pad := a - off%a
off += pad
fields = append(fields, makePad(pad))
}
fields = append(fields, f)
if at, ok := f.(*ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) {
varLen = true
}
if at, ok := f.(*BufferType); ok && (at.Kind == BufferBlobRand || (at.Kind == BufferBlobRange && at.RangeBegin != at.RangeEnd)) {
varLen = true
}
if varLen && i != len(t.Fields)-1 {
panic("embed array in middle of a struct")
}
if !varLen {
off += f.Size()
}
}
if align != 0 && off%align != 0 && !varLen {
pad := align - off%align
off += pad
fields = append(fields, makePad(pad))
}
t.Fields = fields
}
func makePad(sz uintptr) Type {
return &ConstType{
TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false},
TypeSize: sz,
Val: 0,
IsPad: true,
}
}