blob: 6c34f9d56439ddad302b29342ececd325c88f5a0 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// +build ignore
// blockgen generates function definitions for various inspect VMO block types.
//
// All block types share some common header information, but individual block types interpret
// payload data differently. This program generates the block.go file for the inspect package
// such that each block type is properly generated.
package main
import (
"bytes"
"fmt"
"go/format"
"os"
"text/template"
)
// BitField describes information about bit-packed fields for each block. This
// includes the name of the field, the 0-indexed bit position for the start of the
// value, and the 0-indexed bit position of the end of the value.
type BitField struct {
// Name represents the name of this bitfield.
Name string
// BitStart represents the least significant bit's starting position for this field within
// the encompassing value.
BitStart uint
// BitEnd represents the position of the most significant bit for this field within the
// encompassing value.
BitEnd uint
// Type represents the type of the field.
Type string
}
// Mask generates a bitmask for the BitField.
func (b BitField) Mask() uint64 {
bits := b.BitEnd - b.BitStart + 1
mask := (1 << bits) - 1
return uint64(mask << b.BitStart)
}
// BlockInfo describes the layout of a kind of block.
type BlockInfo struct {
// Name represents the name of the type of block being described.
Name string
// HeaderFields describes the bitfields packed into the header quadword.
HeaderFields []BitField
// PayloadFields describes the bitfields packed into the payload quadword.
PayloadFields []BitField
// PayloadOffset describes the position of any additional arbitrary / variable length payload for this block.
PayloadOffset uint64
}
var CommonHeaderFields = []BitField{
{"Order", 0, 3, "BlockOrder"},
{"Type", 4, 7, "BlockType"},
}
func (bi BlockInfo) AllHeaders() []BitField {
return append(CommonHeaderFields, bi.HeaderFields...)
}
var BlockTypes = []BlockInfo{
{Name: "Block"},
{
Name: "FreeBlock",
HeaderFields: []BitField{{"NextFree", 8, 35, "BlockIndex"}},
},
{Name: "ReservedBlock"},
{
Name: "HeaderBlock",
HeaderFields: []BitField{
{"Version", 8, 31, "uint"},
{"Magic", 32, 63, "uint"},
},
},
{
Name: "NodeValueBlock",
HeaderFields: []BitField{
{"ParentIndex", 8, 35, "BlockIndex"},
{"NameIndex", 36, 63, "BlockIndex"},
},
PayloadOffset: 8,
},
{
Name: "IntValueBlock",
HeaderFields: []BitField{
{"ParentIndex", 8, 35, "BlockIndex"},
{"NameIndex", 36, 63, "BlockIndex"},
},
PayloadFields: []BitField{{"Value", 0, 63, "int64"}},
},
{
Name: "UintValueBlock",
HeaderFields: []BitField{
{"ParentIndex", 8, 35, "uint"},
{"NameIndex", 36, 63, "uint"},
},
PayloadFields: []BitField{{"Value", 0, 63, "uint64"}},
},
{
Name: "DoubleValueBlock",
HeaderFields: []BitField{
{"ParentIndex", 8, 35, "BlockIndex"},
{"NameIndex", 36, 63, "BlockIndex"},
},
PayloadFields: []BitField{{"Value", 0, 63, "float64"}},
},
{
Name: "PropertyBlock",
HeaderFields: []BitField{
{"ParentIndex", 8, 35, "BlockIndex"},
{"NameIndex", 36, 63, "BlockIndex"},
},
PayloadFields: []BitField{
{"Length", 0, 31, "uint"},
{"ExtentIndex", 32, 59, "uint"},
{"Flags", 60, 63, "uint"},
},
},
{
Name: "ExtentBlock",
HeaderFields: []BitField{{"NextExtent", 8, 35, "BlockIndex"}},
},
{
Name: "NameBlock",
HeaderFields: []BitField{{"Length", 8, 19, "uint"}},
PayloadOffset: 8,
},
{
Name: "TombstoneBlock",
PayloadFields: []BitField{{"RefCount", 0, 63, "uint64"}},
},
{
Name: "ArrayBlock",
HeaderFields: []BitField{
{"ParentIndex", 8, 35, "BlockIndex"},
{"NameIndex", 36, 63, "BlockIndex"},
},
PayloadFields: []BitField{
{"EntryType", 0, 3, "uint"},
{"Flags", 4, 7, "uint"},
{"Count", 8, 15, "uint"},
},
PayloadOffset: 16,
},
{
Name: "LinkBlock",
PayloadFields: []BitField{
{"ContextIndex", 0, 19, "uint"},
{"Flags", 60, 63, "uint"},
},
},
}
var BlockOrders = []int{16, 32, 64, 128, 256, 512, 1024, 2048}
func main() {
tmpl, err := template.ParseFiles("block.tmpl")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to parse template: %v\n", err)
os.Exit(1)
}
b := bytes.NewBuffer([]byte{})
tmpl.Execute(b, map[string]interface{}{
"BlockTypes": BlockTypes,
"BlockOrders": BlockOrders,
"CommonHeaderFields": CommonHeaderFields,
})
src, err := format.Source(b.Bytes())
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to format source: %v\n", err)
fmt.Fprintf(os.Stderr, "%s\n", b.String())
os.Exit(1)
}
f, err := os.OpenFile("block.go", os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "Couldn't open block.go for writing: %v\n", err)
os.Exit(1)
}
if err := f.Truncate(0); err != nil {
fmt.Fprintf(os.Stderr, "Couldn't truncate block.go: %v\n", err)
os.Exit(1)
}
fmt.Fprint(f, string(src))
}