mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 03:52:24 -05:00 
			
		
		
		
	Bumps [github.com/KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit) from 0.2.4 to 0.2.5. - [Release notes](https://github.com/KimMachineGun/automemlimit/releases) - [Commits](https://github.com/KimMachineGun/automemlimit/compare/v0.2.4...v0.2.5) --- updated-dependencies: - dependency-name: github.com/KimMachineGun/automemlimit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
		
			
				
	
	
		
			319 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			319 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package btf
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| var errNestedTooDeep = errors.New("nested too deep")
 | |
| 
 | |
| // GoFormatter converts a Type to Go syntax.
 | |
| //
 | |
| // A zero GoFormatter is valid to use.
 | |
| type GoFormatter struct {
 | |
| 	w strings.Builder
 | |
| 
 | |
| 	// Types present in this map are referred to using the given name if they
 | |
| 	// are encountered when outputting another type.
 | |
| 	Names map[Type]string
 | |
| 
 | |
| 	// Identifier is called for each field of struct-like types. By default the
 | |
| 	// field name is used as is.
 | |
| 	Identifier func(string) string
 | |
| 
 | |
| 	// EnumIdentifier is called for each element of an enum. By default the
 | |
| 	// name of the enum type is concatenated with Identifier(element).
 | |
| 	EnumIdentifier func(name, element string) string
 | |
| }
 | |
| 
 | |
| // TypeDeclaration generates a Go type declaration for a BTF type.
 | |
| func (gf *GoFormatter) TypeDeclaration(name string, typ Type) (string, error) {
 | |
| 	gf.w.Reset()
 | |
| 	if err := gf.writeTypeDecl(name, typ); err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	return gf.w.String(), nil
 | |
| }
 | |
| 
 | |
| func (gf *GoFormatter) identifier(s string) string {
 | |
| 	if gf.Identifier != nil {
 | |
| 		return gf.Identifier(s)
 | |
| 	}
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (gf *GoFormatter) enumIdentifier(name, element string) string {
 | |
| 	if gf.EnumIdentifier != nil {
 | |
| 		return gf.EnumIdentifier(name, element)
 | |
| 	}
 | |
| 
 | |
| 	return name + gf.identifier(element)
 | |
| }
 | |
| 
 | |
| // writeTypeDecl outputs a declaration of the given type.
 | |
| //
 | |
| // It encodes https://golang.org/ref/spec#Type_declarations:
 | |
| //
 | |
| //     type foo struct { bar uint32; }
 | |
| //     type bar int32
 | |
| func (gf *GoFormatter) writeTypeDecl(name string, typ Type) error {
 | |
| 	if name == "" {
 | |
| 		return fmt.Errorf("need a name for type %s", typ)
 | |
| 	}
 | |
| 
 | |
| 	switch v := skipQualifiers(typ).(type) {
 | |
| 	case *Enum:
 | |
| 		fmt.Fprintf(&gf.w, "type %s ", name)
 | |
| 		switch v.Size {
 | |
| 		case 1:
 | |
| 			gf.w.WriteString("int8")
 | |
| 		case 2:
 | |
| 			gf.w.WriteString("int16")
 | |
| 		case 4:
 | |
| 			gf.w.WriteString("int32")
 | |
| 		case 8:
 | |
| 			gf.w.WriteString("int64")
 | |
| 		default:
 | |
| 			return fmt.Errorf("%s: invalid enum size %d", typ, v.Size)
 | |
| 		}
 | |
| 
 | |
| 		if len(v.Values) == 0 {
 | |
| 			return nil
 | |
| 		}
 | |
| 
 | |
| 		gf.w.WriteString("; const ( ")
 | |
| 		for _, ev := range v.Values {
 | |
| 			id := gf.enumIdentifier(name, ev.Name)
 | |
| 			fmt.Fprintf(&gf.w, "%s %s = %d; ", id, name, ev.Value)
 | |
| 		}
 | |
| 		gf.w.WriteString(")")
 | |
| 
 | |
| 		return nil
 | |
| 
 | |
| 	default:
 | |
| 		fmt.Fprintf(&gf.w, "type %s ", name)
 | |
| 		return gf.writeTypeLit(v, 0)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // writeType outputs the name of a named type or a literal describing the type.
 | |
| //
 | |
| // It encodes https://golang.org/ref/spec#Types.
 | |
| //
 | |
| //     foo                  (if foo is a named type)
 | |
| //     uint32
 | |
| func (gf *GoFormatter) writeType(typ Type, depth int) error {
 | |
| 	typ = skipQualifiers(typ)
 | |
| 
 | |
| 	name := gf.Names[typ]
 | |
| 	if name != "" {
 | |
| 		gf.w.WriteString(name)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return gf.writeTypeLit(typ, depth)
 | |
| }
 | |
| 
 | |
| // writeTypeLit outputs a literal describing the type.
 | |
| //
 | |
| // The function ignores named types.
 | |
| //
 | |
| // It encodes https://golang.org/ref/spec#TypeLit.
 | |
| //
 | |
| //     struct { bar uint32; }
 | |
| //     uint32
 | |
| func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
 | |
| 	depth++
 | |
| 	if depth > maxTypeDepth {
 | |
| 		return errNestedTooDeep
 | |
| 	}
 | |
| 
 | |
| 	var err error
 | |
| 	switch v := skipQualifiers(typ).(type) {
 | |
| 	case *Int:
 | |
| 		gf.writeIntLit(v)
 | |
| 
 | |
| 	case *Enum:
 | |
| 		gf.w.WriteString("int32")
 | |
| 
 | |
| 	case *Typedef:
 | |
| 		err = gf.writeType(v.Type, depth)
 | |
| 
 | |
| 	case *Array:
 | |
| 		fmt.Fprintf(&gf.w, "[%d]", v.Nelems)
 | |
| 		err = gf.writeType(v.Type, depth)
 | |
| 
 | |
| 	case *Struct:
 | |
| 		err = gf.writeStructLit(v.Size, v.Members, depth)
 | |
| 
 | |
| 	case *Union:
 | |
| 		// Always choose the first member to represent the union in Go.
 | |
| 		err = gf.writeStructLit(v.Size, v.Members[:1], depth)
 | |
| 
 | |
| 	case *Datasec:
 | |
| 		err = gf.writeDatasecLit(v, depth)
 | |
| 
 | |
| 	default:
 | |
| 		return fmt.Errorf("type %T: %w", v, ErrNotSupported)
 | |
| 	}
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("%s: %w", typ, err)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (gf *GoFormatter) writeIntLit(i *Int) {
 | |
| 	// NB: Encoding.IsChar is ignored.
 | |
| 	if i.Encoding.IsBool() && i.Size == 1 {
 | |
| 		gf.w.WriteString("bool")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	bits := i.Size * 8
 | |
| 	if i.Encoding.IsSigned() {
 | |
| 		fmt.Fprintf(&gf.w, "int%d", bits)
 | |
| 	} else {
 | |
| 		fmt.Fprintf(&gf.w, "uint%d", bits)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (gf *GoFormatter) writeStructLit(size uint32, members []Member, depth int) error {
 | |
| 	gf.w.WriteString("struct { ")
 | |
| 
 | |
| 	prevOffset := uint32(0)
 | |
| 	skippedBitfield := false
 | |
| 	for i, m := range members {
 | |
| 		if m.BitfieldSize > 0 {
 | |
| 			skippedBitfield = true
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		offset := m.Offset.Bytes()
 | |
| 		if n := offset - prevOffset; skippedBitfield && n > 0 {
 | |
| 			fmt.Fprintf(&gf.w, "_ [%d]byte /* unsupported bitfield */; ", n)
 | |
| 		} else {
 | |
| 			gf.writePadding(n)
 | |
| 		}
 | |
| 
 | |
| 		size, err := Sizeof(m.Type)
 | |
| 		if err != nil {
 | |
| 			return fmt.Errorf("field %d: %w", i, err)
 | |
| 		}
 | |
| 		prevOffset = offset + uint32(size)
 | |
| 
 | |
| 		if err := gf.writeStructField(m, depth); err != nil {
 | |
| 			return fmt.Errorf("field %d: %w", i, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	gf.writePadding(size - prevOffset)
 | |
| 	gf.w.WriteString("}")
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (gf *GoFormatter) writeStructField(m Member, depth int) error {
 | |
| 	if m.BitfieldSize > 0 {
 | |
| 		return fmt.Errorf("bitfields are not supported")
 | |
| 	}
 | |
| 	if m.Offset%8 != 0 {
 | |
| 		return fmt.Errorf("unsupported offset %d", m.Offset)
 | |
| 	}
 | |
| 
 | |
| 	if m.Name == "" {
 | |
| 		// Special case a nested anonymous union like
 | |
| 		//     struct foo { union { int bar; int baz }; }
 | |
| 		// by replacing the whole union with its first member.
 | |
| 		union, ok := m.Type.(*Union)
 | |
| 		if !ok {
 | |
| 			return fmt.Errorf("anonymous fields are not supported")
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 		if len(union.Members) == 0 {
 | |
| 			return errors.New("empty anonymous union")
 | |
| 		}
 | |
| 
 | |
| 		depth++
 | |
| 		if depth > maxTypeDepth {
 | |
| 			return errNestedTooDeep
 | |
| 		}
 | |
| 
 | |
| 		m := union.Members[0]
 | |
| 		size, err := Sizeof(m.Type)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		if err := gf.writeStructField(m, depth); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		gf.writePadding(union.Size - uint32(size))
 | |
| 		return nil
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	fmt.Fprintf(&gf.w, "%s ", gf.identifier(m.Name))
 | |
| 
 | |
| 	if err := gf.writeType(m.Type, depth); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	gf.w.WriteString("; ")
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (gf *GoFormatter) writeDatasecLit(ds *Datasec, depth int) error {
 | |
| 	gf.w.WriteString("struct { ")
 | |
| 
 | |
| 	prevOffset := uint32(0)
 | |
| 	for i, vsi := range ds.Vars {
 | |
| 		v := vsi.Type.(*Var)
 | |
| 		if v.Linkage != GlobalVar {
 | |
| 			// Ignore static, extern, etc. for now.
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if v.Name == "" {
 | |
| 			return fmt.Errorf("variable %d: empty name", i)
 | |
| 		}
 | |
| 
 | |
| 		gf.writePadding(vsi.Offset - prevOffset)
 | |
| 		prevOffset = vsi.Offset + vsi.Size
 | |
| 
 | |
| 		fmt.Fprintf(&gf.w, "%s ", gf.identifier(v.Name))
 | |
| 
 | |
| 		if err := gf.writeType(v.Type, depth); err != nil {
 | |
| 			return fmt.Errorf("variable %d: %w", i, err)
 | |
| 		}
 | |
| 
 | |
| 		gf.w.WriteString("; ")
 | |
| 	}
 | |
| 
 | |
| 	gf.writePadding(ds.Size - prevOffset)
 | |
| 	gf.w.WriteString("}")
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (gf *GoFormatter) writePadding(bytes uint32) {
 | |
| 	if bytes > 0 {
 | |
| 		fmt.Fprintf(&gf.w, "_ [%d]byte; ", bytes)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func skipQualifiers(typ Type) Type {
 | |
| 	result := typ
 | |
| 	for depth := 0; depth <= maxTypeDepth; depth++ {
 | |
| 		switch v := (result).(type) {
 | |
| 		case qualifier:
 | |
| 			result = v.qualify()
 | |
| 		default:
 | |
| 			return result
 | |
| 		}
 | |
| 	}
 | |
| 	return &cycle{typ}
 | |
| }
 |