1 // structlayout displays the layout (field sizes and padding) of structs.
13 "honnef.co/go/tools/gcsizes"
14 st "honnef.co/go/tools/structlayout"
15 "honnef.co/go/tools/version"
17 "golang.org/x/tools/go/loader"
26 flag.BoolVar(&fJSON, "json", false, "Format data as JSON")
27 flag.BoolVar(&fVersion, "version", false, "Print version and exit")
39 if len(flag.Args()) != 2 {
44 conf := loader.Config{
45 Build: &build.Default,
51 typName = flag.Args()[1]
54 lprog, err := conf.Load()
59 obj := lprog.Package(pkg).Pkg.Scope().Lookup(typName)
61 log.Fatal("couldn't find type")
65 st, ok := typ.Underlying().(*types.Struct)
67 log.Fatal("identifier is not a struct type")
70 fields := sizes(st, typ.(*types.Named).Obj().Name(), 0, nil)
78 func emitJSON(fields []st.Field) {
82 json.NewEncoder(os.Stdout).Encode(fields)
85 func emitText(fields []st.Field) {
86 for _, field := range fields {
90 func sizes(typ *types.Struct, prefix string, base int64, out []st.Field) []st.Field {
91 s := gcsizes.ForArch(build.Default.GOARCH)
93 var fields []*types.Var
94 for i := 0; i < n; i++ {
95 fields = append(fields, typ.Field(i))
97 offsets := s.Offsetsof(fields)
98 for i := range offsets {
103 for i, field := range fields {
104 if offsets[i] > pos {
105 padding := offsets[i] - pos
106 out = append(out, st.Field{
114 size := s.Sizeof(field.Type())
115 if typ2, ok := field.Type().Underlying().(*types.Struct); ok && typ2.NumFields() != 0 {
116 out = sizes(typ2, prefix+"."+field.Name(), pos, out)
118 out = append(out, st.Field{
119 Name: prefix + "." + field.Name(),
120 Type: field.Type().String(),
122 End: offsets[i] + size,
124 Align: s.Alignof(field.Type()),
133 field := &out[len(out)-1]
138 pad := s.Sizeof(typ) - field.End
140 out = append(out, st.Field{
143 End: field.End + pad,