+++ /dev/null
-// structlayout displays the layout (field sizes and padding) of structs.
-package main
-
-import (
- "encoding/json"
- "flag"
- "fmt"
- "go/build"
- "go/types"
- "log"
- "os"
-
- "honnef.co/go/tools/gcsizes"
- st "honnef.co/go/tools/structlayout"
- "honnef.co/go/tools/version"
-
- "golang.org/x/tools/go/loader"
-)
-
-var (
- fJSON bool
- fVersion bool
-)
-
-func init() {
- flag.BoolVar(&fJSON, "json", false, "Format data as JSON")
- flag.BoolVar(&fVersion, "version", false, "Print version and exit")
-}
-
-func main() {
- log.SetFlags(0)
- flag.Parse()
-
- if fVersion {
- version.Print()
- os.Exit(0)
- }
-
- if len(flag.Args()) != 2 {
- flag.Usage()
- os.Exit(1)
- }
-
- conf := loader.Config{
- Build: &build.Default,
- }
-
- var pkg string
- var typName string
- pkg = flag.Args()[0]
- typName = flag.Args()[1]
- conf.Import(pkg)
-
- lprog, err := conf.Load()
- if err != nil {
- log.Fatal(err)
- }
- var typ types.Type
- obj := lprog.Package(pkg).Pkg.Scope().Lookup(typName)
- if obj == nil {
- log.Fatal("couldn't find type")
- }
- typ = obj.Type()
-
- st, ok := typ.Underlying().(*types.Struct)
- if !ok {
- log.Fatal("identifier is not a struct type")
- }
-
- fields := sizes(st, typ.(*types.Named).Obj().Name(), 0, nil)
- if fJSON {
- emitJSON(fields)
- } else {
- emitText(fields)
- }
-}
-
-func emitJSON(fields []st.Field) {
- if fields == nil {
- fields = []st.Field{}
- }
- json.NewEncoder(os.Stdout).Encode(fields)
-}
-
-func emitText(fields []st.Field) {
- for _, field := range fields {
- fmt.Println(field)
- }
-}
-func sizes(typ *types.Struct, prefix string, base int64, out []st.Field) []st.Field {
- s := gcsizes.ForArch(build.Default.GOARCH)
- n := typ.NumFields()
- var fields []*types.Var
- for i := 0; i < n; i++ {
- fields = append(fields, typ.Field(i))
- }
- offsets := s.Offsetsof(fields)
- for i := range offsets {
- offsets[i] += base
- }
-
- pos := base
- for i, field := range fields {
- if offsets[i] > pos {
- padding := offsets[i] - pos
- out = append(out, st.Field{
- IsPadding: true,
- Start: pos,
- End: pos + padding,
- Size: padding,
- })
- pos += padding
- }
- size := s.Sizeof(field.Type())
- if typ2, ok := field.Type().Underlying().(*types.Struct); ok && typ2.NumFields() != 0 {
- out = sizes(typ2, prefix+"."+field.Name(), pos, out)
- } else {
- out = append(out, st.Field{
- Name: prefix + "." + field.Name(),
- Type: field.Type().String(),
- Start: offsets[i],
- End: offsets[i] + size,
- Size: size,
- Align: s.Alignof(field.Type()),
- })
- }
- pos += size
- }
-
- if len(out) == 0 {
- return out
- }
- field := &out[len(out)-1]
- if field.Size == 0 {
- field.Size = 1
- field.End++
- }
- pad := s.Sizeof(typ) - field.End
- if pad > 0 {
- out = append(out, st.Field{
- IsPadding: true,
- Start: field.End,
- End: field.End + pad,
- Size: pad,
- })
- }
-
- return out
-}