Skip to content

Commit

Permalink
btf: add String method to Type
Browse files Browse the repository at this point in the history
Give types a useful printable representation:

    === RUN   TestType/*btf.Void
        types_test.go:121: void#0
    === RUN   TestType/*btf.Int
        types_test.go:121: uint16#0[bits=3]
    === RUN   TestType/*btf.Pointer
        types_test.go:121: pointer#0[target=#0]
    === RUN   TestType/*btf.Array
        types_test.go:121: array#0[type=#0 n=0]
    === RUN   TestType/*btf.Struct
        types_test.go:121: struct#0[""]
    === RUN   TestType/*btf.Union
        types_test.go:121: union#0[""]
    === RUN   TestType/*btf.Enum
        types_test.go:121: enum#0[""]
    === RUN   TestType/*btf.Fwd
        types_test.go:121: fwd#0[struct "thunk"]
    === RUN   TestType/*btf.Typedef
        types_test.go:121: typedef#0["" #0]
    === RUN   TestType/*btf.Volatile
        types_test.go:121: volatile#0[#0]
    === RUN   TestType/*btf.Const
        types_test.go:121: const#0[#0]
    === RUN   TestType/*btf.Restrict
        types_test.go:121: restrict#0[#0]
    === RUN   TestType/*btf.Func
        types_test.go:121: func#0["foo" proto=#0]
    === RUN   TestType/*btf.FuncProto
        types_test.go:121: proto#0["bar"=#0, return=#0]
    === RUN   TestType/*btf.Var
        types_test.go:121: var#0[""]
    === RUN   TestType/*btf.Datasec
        types_test.go:121: section#0[""]

The rough format is

    <type>#<type id>[<other information>].

It is intentionally different from the in-kernel BTF log output:

    [type id] <type> <name> <other>

This is intentional, since we don't know where and how a user
might embed a stringified type. A more compact format seems
better here.

We can always add a dedicated function that prints a []Type in
kernel style if we find that necessary.
  • Loading branch information
lmb committed Nov 27, 2020
1 parent e8edbe1 commit 6581b5d
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 2 deletions.
120 changes: 119 additions & 1 deletion internal/btf/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ func (tid TypeID) ID() TypeID {
type Type interface {
ID() TypeID

String() string

// Make a copy of the type, without copying Type members.
copy() Type

Expand Down Expand Up @@ -50,6 +52,7 @@ func (n Name) name() string {
type Void struct{}

func (v *Void) ID() TypeID { return 0 }
func (v *Void) String() string { return "void#0" }
func (v *Void) size() uint32 { return 0 }
func (v *Void) copy() Type { return (*Void)(nil) }
func (v *Void) walk(*copyStack) {}
Expand Down Expand Up @@ -78,6 +81,31 @@ type Int struct {

var _ namedType = (*Int)(nil)

func (i *Int) String() string {
var s strings.Builder

switch {
case i.Encoding&Char != 0:
s.WriteString("char")
case i.Encoding&Bool != 0:
s.WriteString("bool")
default:
if i.Encoding&Signed == 0 {
s.WriteRune('u')
}
s.WriteString("int")
fmt.Fprintf(&s, "%d", i.Size*8)
}

fmt.Fprintf(&s, "#%d", i.TypeID)

if i.Bits > 0 {
fmt.Fprintf(&s, "[bits=%d]", i.Bits)
}

return s.String()
}

func (i *Int) size() uint32 { return i.Size }
func (i *Int) walk(*copyStack) {}
func (i *Int) copy() Type {
Expand All @@ -91,6 +119,10 @@ type Pointer struct {
Target Type
}

func (p *Pointer) String() string {
return fmt.Sprintf("pointer#%d[target=#%d]", p.TypeID, p.Target.ID())
}

func (p *Pointer) size() uint32 { return 8 }
func (p *Pointer) walk(cs *copyStack) { cs.push(&p.Target) }
func (p *Pointer) copy() Type {
Expand All @@ -105,6 +137,10 @@ type Array struct {
Nelems uint32
}

func (arr *Array) String() string {
return fmt.Sprintf("array#%d[type=#%d n=%d]", arr.TypeID, arr.Type.ID(), arr.Nelems)
}

func (arr *Array) walk(cs *copyStack) { cs.push(&arr.Type) }
func (arr *Array) copy() Type {
cpy := *arr
Expand All @@ -120,6 +156,10 @@ type Struct struct {
Members []Member
}

func (s *Struct) String() string {
return fmt.Sprintf("struct#%d[%q]", s.TypeID, s.Name)
}

func (s *Struct) size() uint32 { return s.Size }

func (s *Struct) walk(cs *copyStack) {
Expand Down Expand Up @@ -148,6 +188,10 @@ type Union struct {
Members []Member
}

func (u *Union) String() string {
return fmt.Sprintf("union#%d[%q]", u.TypeID, u.Name)
}

func (u *Union) size() uint32 { return u.Size }

func (u *Union) walk(cs *copyStack) {
Expand Down Expand Up @@ -194,6 +238,10 @@ type Enum struct {
Values []EnumValue
}

func (e *Enum) String() string {
return fmt.Sprintf("enum#%d[%q]", e.TypeID, e.Name)
}

// EnumValue is part of an Enum
//
// Is is not a valid Type
Expand All @@ -211,10 +259,35 @@ func (e *Enum) copy() Type {
return &cpy
}

// FwdKind is the type of forward declaration.
type FwdKind int

// Valid types of forward declaration.
const (
FwdStruct FwdKind = iota
FwdUnion
)

func (fk FwdKind) String() string {
switch fk {
case FwdStruct:
return "struct"
case FwdUnion:
return "union"
default:
return fmt.Sprintf("%T(%d)", fk, int(fk))
}
}

// Fwd is a forward declaration of a Type.
type Fwd struct {
TypeID
Name
Kind FwdKind
}

func (f *Fwd) String() string {
return fmt.Sprintf("fwd#%d[%s %q]", f.TypeID, f.Kind, f.Name)
}

func (f *Fwd) walk(*copyStack) {}
Expand All @@ -230,6 +303,10 @@ type Typedef struct {
Type Type
}

func (td *Typedef) String() string {
return fmt.Sprintf("typedef#%d[%q #%d]", td.TypeID, td.Name, td.Type.ID())
}

func (td *Typedef) walk(cs *copyStack) { cs.push(&td.Type) }
func (td *Typedef) copy() Type {
cpy := *td
Expand All @@ -242,6 +319,10 @@ type Volatile struct {
Type Type
}

func (v *Volatile) String() string {
return fmt.Sprintf("volatile#%d[#%d]", v.TypeID, v.Type.ID())
}

func (v *Volatile) qualify() Type { return v.Type }
func (v *Volatile) walk(cs *copyStack) { cs.push(&v.Type) }
func (v *Volatile) copy() Type {
Expand All @@ -255,6 +336,10 @@ type Const struct {
Type Type
}

func (c *Const) String() string {
return fmt.Sprintf("const#%d[#%d]", c.TypeID, c.Type.ID())
}

func (c *Const) qualify() Type { return c.Type }
func (c *Const) walk(cs *copyStack) { cs.push(&c.Type) }
func (c *Const) copy() Type {
Expand All @@ -268,6 +353,10 @@ type Restrict struct {
Type Type
}

func (r *Restrict) String() string {
return fmt.Sprintf("restrict#%d[#%d]", r.TypeID, r.Type.ID())
}

func (r *Restrict) qualify() Type { return r.Type }
func (r *Restrict) walk(cs *copyStack) { cs.push(&r.Type) }
func (r *Restrict) copy() Type {
Expand All @@ -282,6 +371,10 @@ type Func struct {
Type Type
}

func (f *Func) String() string {
return fmt.Sprintf("func#%d[%q proto=#%d]", f.TypeID, f.Name, f.Type.ID())
}

func (f *Func) walk(cs *copyStack) { cs.push(&f.Type) }
func (f *Func) copy() Type {
cpy := *f
Expand All @@ -295,6 +388,16 @@ type FuncProto struct {
Params []FuncParam
}

func (fp *FuncProto) String() string {
var s strings.Builder
fmt.Fprintf(&s, "proto#%d[", fp.TypeID)
for _, param := range fp.Params {
fmt.Fprintf(&s, "%q=#%d, ", param.Name, param.Type.ID())
}
fmt.Fprintf(&s, "return=#%d]", fp.Return.ID())
return s.String()
}

func (fp *FuncProto) walk(cs *copyStack) {
cs.push(&fp.Return)
for i := range fp.Params {
Expand All @@ -321,6 +424,11 @@ type Var struct {
Type Type
}

func (v *Var) String() string {
// TODO: Linkage
return fmt.Sprintf("var#%d[%q]", v.TypeID, v.Name)
}

func (v *Var) walk(cs *copyStack) { cs.push(&v.Type) }
func (v *Var) copy() Type {
cpy := *v
Expand All @@ -335,6 +443,10 @@ type Datasec struct {
Vars []VarSecinfo
}

func (ds *Datasec) String() string {
return fmt.Sprintf("section#%d[%q]", ds.TypeID, ds.Name)
}

func (ds *Datasec) size() uint32 { return ds.Size }

func (ds *Datasec) walk(cs *copyStack) {
Expand All @@ -351,6 +463,8 @@ func (ds *Datasec) copy() Type {
}

// VarSecinfo describes variable in a Datasec
//
// It is not a valid Type.
type VarSecinfo struct {
Type Type
Offset uint32
Expand Down Expand Up @@ -589,7 +703,11 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
typ = &Enum{id, name, vals}

case kindForward:
typ = &Fwd{id, name}
if raw.KindFlag() {
typ = &Fwd{id, name, FwdUnion}
} else {
typ = &Fwd{id, name, FwdStruct}
}

case kindTypedef:
typedef := &Typedef{id, name, nil}
Expand Down
4 changes: 3 additions & 1 deletion internal/btf/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func ExampleType_validTypes() {
func TestType(t *testing.T) {
types := []func() Type{
func() Type { return &Void{} },
func() Type { return &Int{} },
func() Type { return &Int{Size: 2, Bits: 3} },
func() Type { return &Pointer{Target: &Void{}} },
func() Type { return &Array{Type: &Int{}} },
func() Type {
Expand Down Expand Up @@ -118,6 +118,8 @@ func TestType(t *testing.T) {
for _, fn := range types {
typ := fn()
t.Run(fmt.Sprintf("%T", typ), func(t *testing.T) {
t.Logf("%v", typ)

if typ == typ.copy() {
t.Error("Copy doesn't copy")
}
Expand Down

0 comments on commit 6581b5d

Please sign in to comment.