github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/btf.go (about)

     1  package btf
     2  
     3  import (
     4  	"bufio"
     5  	"debug/elf"
     6  	"encoding/binary"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"math"
    11  	"os"
    12  	"reflect"
    13  	"sync"
    14  
    15  	"github.com/cilium/ebpf/internal"
    16  	"github.com/cilium/ebpf/internal/sys"
    17  )
    18  
    19  const btfMagic = 0xeB9F
    20  
    21  // Errors returned by BTF functions.
    22  var (
    23  	ErrNotSupported    = internal.ErrNotSupported
    24  	ErrNotFound        = errors.New("not found")
    25  	ErrNoExtendedInfo  = errors.New("no extended info")
    26  	ErrMultipleMatches = errors.New("multiple matching types")
    27  )
    28  
    29  // ID represents the unique ID of a BTF object.
    30  type ID = sys.BTFID
    31  
    32  // immutableTypes is a set of types which musn't be changed.
    33  type immutableTypes struct {
    34  	// All types contained by the spec, not including types from the base in
    35  	// case the spec was parsed from split BTF.
    36  	types []Type
    37  
    38  	// Type IDs indexed by type.
    39  	typeIDs map[Type]TypeID
    40  
    41  	// The ID of the first type in types.
    42  	firstTypeID TypeID
    43  
    44  	// Types indexed by essential name.
    45  	// Includes all struct flavors and types with the same name.
    46  	namedTypes map[essentialName][]TypeID
    47  
    48  	// Byte order of the types. This affects things like struct member order
    49  	// when using bitfields.
    50  	byteOrder binary.ByteOrder
    51  }
    52  
    53  func (s *immutableTypes) typeByID(id TypeID) (Type, bool) {
    54  	if id < s.firstTypeID {
    55  		return nil, false
    56  	}
    57  
    58  	index := int(id - s.firstTypeID)
    59  	if index >= len(s.types) {
    60  		return nil, false
    61  	}
    62  
    63  	return s.types[index], true
    64  }
    65  
    66  // mutableTypes is a set of types which may be changed.
    67  type mutableTypes struct {
    68  	imm           immutableTypes
    69  	mu            *sync.RWMutex   // protects copies below
    70  	copies        map[Type]Type   // map[orig]copy
    71  	copiedTypeIDs map[Type]TypeID // map[copy]origID
    72  }
    73  
    74  // add a type to the set of mutable types.
    75  //
    76  // Copies type and all of its children once. Repeated calls with the same type
    77  // do not copy again.
    78  func (mt *mutableTypes) add(typ Type, typeIDs map[Type]TypeID) Type {
    79  	mt.mu.RLock()
    80  	cpy, ok := mt.copies[typ]
    81  	mt.mu.RUnlock()
    82  
    83  	if ok {
    84  		// Fast path: the type has been copied before.
    85  		return cpy
    86  	}
    87  
    88  	// modifyGraphPreorder copies the type graph node by node, so we can't drop
    89  	// the lock in between.
    90  	mt.mu.Lock()
    91  	defer mt.mu.Unlock()
    92  
    93  	return copyType(typ, typeIDs, mt.copies, mt.copiedTypeIDs)
    94  }
    95  
    96  // copy a set of mutable types.
    97  func (mt *mutableTypes) copy() mutableTypes {
    98  	mtCopy := mutableTypes{
    99  		mt.imm,
   100  		&sync.RWMutex{},
   101  		make(map[Type]Type, len(mt.copies)),
   102  		make(map[Type]TypeID, len(mt.copiedTypeIDs)),
   103  	}
   104  
   105  	// Prevent concurrent modification of mt.copiedTypeIDs.
   106  	mt.mu.RLock()
   107  	defer mt.mu.RUnlock()
   108  
   109  	copiesOfCopies := make(map[Type]Type, len(mt.copies))
   110  	for orig, copy := range mt.copies {
   111  		// NB: We make a copy of copy, not orig, so that changes to mutable types
   112  		// are preserved.
   113  		copyOfCopy := copyType(copy, mt.copiedTypeIDs, copiesOfCopies, mtCopy.copiedTypeIDs)
   114  		mtCopy.copies[orig] = copyOfCopy
   115  	}
   116  
   117  	return mtCopy
   118  }
   119  
   120  func (mt *mutableTypes) typeID(typ Type) (TypeID, error) {
   121  	if _, ok := typ.(*Void); ok {
   122  		// Equality is weird for void, since it is a zero sized type.
   123  		return 0, nil
   124  	}
   125  
   126  	mt.mu.RLock()
   127  	defer mt.mu.RUnlock()
   128  
   129  	id, ok := mt.copiedTypeIDs[typ]
   130  	if !ok {
   131  		return 0, fmt.Errorf("no ID for type %s: %w", typ, ErrNotFound)
   132  	}
   133  
   134  	return id, nil
   135  }
   136  
   137  func (mt *mutableTypes) typeByID(id TypeID) (Type, bool) {
   138  	immT, ok := mt.imm.typeByID(id)
   139  	if !ok {
   140  		return nil, false
   141  	}
   142  
   143  	return mt.add(immT, mt.imm.typeIDs), true
   144  }
   145  
   146  func (mt *mutableTypes) anyTypesByName(name string) ([]Type, error) {
   147  	immTypes := mt.imm.namedTypes[newEssentialName(name)]
   148  	if len(immTypes) == 0 {
   149  		return nil, fmt.Errorf("type name %s: %w", name, ErrNotFound)
   150  	}
   151  
   152  	// Return a copy to prevent changes to namedTypes.
   153  	result := make([]Type, 0, len(immTypes))
   154  	for _, id := range immTypes {
   155  		immT, ok := mt.imm.typeByID(id)
   156  		if !ok {
   157  			return nil, fmt.Errorf("no type with ID %d", id)
   158  		}
   159  
   160  		// Match against the full name, not just the essential one
   161  		// in case the type being looked up is a struct flavor.
   162  		if immT.TypeName() == name {
   163  			result = append(result, mt.add(immT, mt.imm.typeIDs))
   164  		}
   165  	}
   166  	return result, nil
   167  }
   168  
   169  // Spec allows querying a set of Types and loading the set into the
   170  // kernel.
   171  type Spec struct {
   172  	mutableTypes
   173  
   174  	// String table from ELF.
   175  	strings *stringTable
   176  }
   177  
   178  // LoadSpec opens file and calls LoadSpecFromReader on it.
   179  func LoadSpec(file string) (*Spec, error) {
   180  	fh, err := os.Open(file)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	defer fh.Close()
   185  
   186  	return LoadSpecFromReader(fh)
   187  }
   188  
   189  // LoadSpecFromReader reads from an ELF or a raw BTF blob.
   190  //
   191  // Returns ErrNotFound if reading from an ELF which contains no BTF. ExtInfos
   192  // may be nil.
   193  func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
   194  	file, err := internal.NewSafeELFFile(rd)
   195  	if err != nil {
   196  		if bo := guessRawBTFByteOrder(rd); bo != nil {
   197  			return loadRawSpec(io.NewSectionReader(rd, 0, math.MaxInt64), bo, nil)
   198  		}
   199  
   200  		return nil, err
   201  	}
   202  
   203  	return loadSpecFromELF(file)
   204  }
   205  
   206  // LoadSpecAndExtInfosFromReader reads from an ELF.
   207  //
   208  // ExtInfos may be nil if the ELF doesn't contain section metadata.
   209  // Returns ErrNotFound if the ELF contains no BTF.
   210  func LoadSpecAndExtInfosFromReader(rd io.ReaderAt) (*Spec, *ExtInfos, error) {
   211  	file, err := internal.NewSafeELFFile(rd)
   212  	if err != nil {
   213  		return nil, nil, err
   214  	}
   215  
   216  	spec, err := loadSpecFromELF(file)
   217  	if err != nil {
   218  		return nil, nil, err
   219  	}
   220  
   221  	extInfos, err := loadExtInfosFromELF(file, spec)
   222  	if err != nil && !errors.Is(err, ErrNotFound) {
   223  		return nil, nil, err
   224  	}
   225  
   226  	return spec, extInfos, nil
   227  }
   228  
   229  // symbolOffsets extracts all symbols offsets from an ELF and indexes them by
   230  // section and variable name.
   231  //
   232  // References to variables in BTF data sections carry unsigned 32-bit offsets.
   233  // Some ELF symbols (e.g. in vmlinux) may point to virtual memory that is well
   234  // beyond this range. Since these symbols cannot be described by BTF info,
   235  // ignore them here.
   236  func symbolOffsets(file *internal.SafeELFFile) (map[symbol]uint32, error) {
   237  	symbols, err := file.Symbols()
   238  	if err != nil {
   239  		return nil, fmt.Errorf("can't read symbols: %v", err)
   240  	}
   241  
   242  	offsets := make(map[symbol]uint32)
   243  	for _, sym := range symbols {
   244  		if idx := sym.Section; idx >= elf.SHN_LORESERVE && idx <= elf.SHN_HIRESERVE {
   245  			// Ignore things like SHN_ABS
   246  			continue
   247  		}
   248  
   249  		if sym.Value > math.MaxUint32 {
   250  			// VarSecinfo offset is u32, cannot reference symbols in higher regions.
   251  			continue
   252  		}
   253  
   254  		if int(sym.Section) >= len(file.Sections) {
   255  			return nil, fmt.Errorf("symbol %s: invalid section %d", sym.Name, sym.Section)
   256  		}
   257  
   258  		secName := file.Sections[sym.Section].Name
   259  		offsets[symbol{secName, sym.Name}] = uint32(sym.Value)
   260  	}
   261  
   262  	return offsets, nil
   263  }
   264  
   265  func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) {
   266  	var (
   267  		btfSection   *elf.Section
   268  		sectionSizes = make(map[string]uint32)
   269  	)
   270  
   271  	for _, sec := range file.Sections {
   272  		switch sec.Name {
   273  		case ".BTF":
   274  			btfSection = sec
   275  		default:
   276  			if sec.Type != elf.SHT_PROGBITS && sec.Type != elf.SHT_NOBITS {
   277  				break
   278  			}
   279  
   280  			if sec.Size > math.MaxUint32 {
   281  				return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name)
   282  			}
   283  
   284  			sectionSizes[sec.Name] = uint32(sec.Size)
   285  		}
   286  	}
   287  
   288  	if btfSection == nil {
   289  		return nil, fmt.Errorf("btf: %w", ErrNotFound)
   290  	}
   291  
   292  	offsets, err := symbolOffsets(file)
   293  	if err != nil {
   294  		return nil, err
   295  	}
   296  
   297  	if btfSection.ReaderAt == nil {
   298  		return nil, fmt.Errorf("compressed BTF is not supported")
   299  	}
   300  
   301  	spec, err := loadRawSpec(btfSection.ReaderAt, file.ByteOrder, nil)
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  
   306  	err = fixupDatasec(spec.imm.types, sectionSizes, offsets)
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  
   311  	return spec, nil
   312  }
   313  
   314  func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error) {
   315  	var (
   316  		baseStrings *stringTable
   317  		firstTypeID TypeID
   318  		err         error
   319  	)
   320  
   321  	if base != nil {
   322  		if base.imm.firstTypeID != 0 {
   323  			return nil, fmt.Errorf("can't use split BTF as base")
   324  		}
   325  
   326  		baseStrings = base.strings
   327  
   328  		firstTypeID, err = base.nextTypeID()
   329  		if err != nil {
   330  			return nil, err
   331  		}
   332  	}
   333  
   334  	types, rawStrings, err := parseBTF(btf, bo, baseStrings, base)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  
   339  	typeIDs, typesByName := indexTypes(types, firstTypeID)
   340  
   341  	return &Spec{
   342  		mutableTypes{
   343  			immutableTypes{
   344  				types,
   345  				typeIDs,
   346  				firstTypeID,
   347  				typesByName,
   348  				bo,
   349  			},
   350  			&sync.RWMutex{},
   351  			make(map[Type]Type),
   352  			make(map[Type]TypeID),
   353  		},
   354  		rawStrings,
   355  	}, nil
   356  }
   357  
   358  func indexTypes(types []Type, firstTypeID TypeID) (map[Type]TypeID, map[essentialName][]TypeID) {
   359  	namedTypes := 0
   360  	for _, typ := range types {
   361  		if typ.TypeName() != "" {
   362  			// Do a pre-pass to figure out how big types by name has to be.
   363  			// Most types have unique names, so it's OK to ignore essentialName
   364  			// here.
   365  			namedTypes++
   366  		}
   367  	}
   368  
   369  	typeIDs := make(map[Type]TypeID, len(types))
   370  	typesByName := make(map[essentialName][]TypeID, namedTypes)
   371  
   372  	for i, typ := range types {
   373  		id := firstTypeID + TypeID(i)
   374  		typeIDs[typ] = id
   375  
   376  		if name := newEssentialName(typ.TypeName()); name != "" {
   377  			typesByName[name] = append(typesByName[name], id)
   378  		}
   379  	}
   380  
   381  	return typeIDs, typesByName
   382  }
   383  
   384  func guessRawBTFByteOrder(r io.ReaderAt) binary.ByteOrder {
   385  	buf := new(bufio.Reader)
   386  	for _, bo := range []binary.ByteOrder{
   387  		binary.LittleEndian,
   388  		binary.BigEndian,
   389  	} {
   390  		buf.Reset(io.NewSectionReader(r, 0, math.MaxInt64))
   391  		if _, err := parseBTFHeader(buf, bo); err == nil {
   392  			return bo
   393  		}
   394  	}
   395  
   396  	return nil
   397  }
   398  
   399  // parseBTF reads a .BTF section into memory and parses it into a list of
   400  // raw types and a string table.
   401  func parseBTF(btf io.ReaderAt, bo binary.ByteOrder, baseStrings *stringTable, base *Spec) ([]Type, *stringTable, error) {
   402  	buf := internal.NewBufferedSectionReader(btf, 0, math.MaxInt64)
   403  	header, err := parseBTFHeader(buf, bo)
   404  	if err != nil {
   405  		return nil, nil, fmt.Errorf("parsing .BTF header: %v", err)
   406  	}
   407  
   408  	rawStrings, err := readStringTable(io.NewSectionReader(btf, header.stringStart(), int64(header.StringLen)),
   409  		baseStrings)
   410  	if err != nil {
   411  		return nil, nil, fmt.Errorf("can't read type names: %w", err)
   412  	}
   413  
   414  	buf.Reset(io.NewSectionReader(btf, header.typeStart(), int64(header.TypeLen)))
   415  	types, err := readAndInflateTypes(buf, bo, header.TypeLen, rawStrings, base)
   416  	if err != nil {
   417  		return nil, nil, err
   418  	}
   419  
   420  	return types, rawStrings, nil
   421  }
   422  
   423  type symbol struct {
   424  	section string
   425  	name    string
   426  }
   427  
   428  // fixupDatasec attempts to patch up missing info in Datasecs and its members by
   429  // supplementing them with information from the ELF headers and symbol table.
   430  func fixupDatasec(types []Type, sectionSizes map[string]uint32, offsets map[symbol]uint32) error {
   431  	for _, typ := range types {
   432  		ds, ok := typ.(*Datasec)
   433  		if !ok {
   434  			continue
   435  		}
   436  
   437  		name := ds.Name
   438  
   439  		// Some Datasecs are virtual and don't have corresponding ELF sections.
   440  		switch name {
   441  		case ".ksyms":
   442  			// .ksyms describes forward declarations of kfunc signatures.
   443  			// Nothing to fix up, all sizes and offsets are 0.
   444  			for _, vsi := range ds.Vars {
   445  				_, ok := vsi.Type.(*Func)
   446  				if !ok {
   447  					// Only Funcs are supported in the .ksyms Datasec.
   448  					return fmt.Errorf("data section %s: expected *btf.Func, not %T: %w", name, vsi.Type, ErrNotSupported)
   449  				}
   450  			}
   451  
   452  			continue
   453  		case ".kconfig":
   454  			// .kconfig has a size of 0 and has all members' offsets set to 0.
   455  			// Fix up all offsets and set the Datasec's size.
   456  			if err := fixupDatasecLayout(ds); err != nil {
   457  				return err
   458  			}
   459  
   460  			// Fix up extern to global linkage to avoid a BTF verifier error.
   461  			for _, vsi := range ds.Vars {
   462  				vsi.Type.(*Var).Linkage = GlobalVar
   463  			}
   464  
   465  			continue
   466  		}
   467  
   468  		if ds.Size != 0 {
   469  			continue
   470  		}
   471  
   472  		ds.Size, ok = sectionSizes[name]
   473  		if !ok {
   474  			return fmt.Errorf("data section %s: missing size", name)
   475  		}
   476  
   477  		for i := range ds.Vars {
   478  			symName := ds.Vars[i].Type.TypeName()
   479  			ds.Vars[i].Offset, ok = offsets[symbol{name, symName}]
   480  			if !ok {
   481  				return fmt.Errorf("data section %s: missing offset for symbol %s", name, symName)
   482  			}
   483  		}
   484  	}
   485  
   486  	return nil
   487  }
   488  
   489  // fixupDatasecLayout populates ds.Vars[].Offset according to var sizes and
   490  // alignment. Calculate and set ds.Size.
   491  func fixupDatasecLayout(ds *Datasec) error {
   492  	var off uint32
   493  
   494  	for i, vsi := range ds.Vars {
   495  		v, ok := vsi.Type.(*Var)
   496  		if !ok {
   497  			return fmt.Errorf("member %d: unsupported type %T", i, vsi.Type)
   498  		}
   499  
   500  		size, err := Sizeof(v.Type)
   501  		if err != nil {
   502  			return fmt.Errorf("variable %s: getting size: %w", v.Name, err)
   503  		}
   504  		align, err := alignof(v.Type)
   505  		if err != nil {
   506  			return fmt.Errorf("variable %s: getting alignment: %w", v.Name, err)
   507  		}
   508  
   509  		// Align the current member based on the offset of the end of the previous
   510  		// member and the alignment of the current member.
   511  		off = internal.Align(off, uint32(align))
   512  
   513  		ds.Vars[i].Offset = off
   514  
   515  		off += uint32(size)
   516  	}
   517  
   518  	ds.Size = off
   519  
   520  	return nil
   521  }
   522  
   523  // Copy creates a copy of Spec.
   524  func (s *Spec) Copy() *Spec {
   525  	return &Spec{
   526  		s.mutableTypes.copy(),
   527  		s.strings,
   528  	}
   529  }
   530  
   531  type sliceWriter []byte
   532  
   533  func (sw sliceWriter) Write(p []byte) (int, error) {
   534  	if len(p) != len(sw) {
   535  		return 0, errors.New("size doesn't match")
   536  	}
   537  
   538  	return copy(sw, p), nil
   539  }
   540  
   541  // nextTypeID returns the next unallocated type ID or an error if there are no
   542  // more type IDs.
   543  func (s *Spec) nextTypeID() (TypeID, error) {
   544  	id := s.imm.firstTypeID + TypeID(len(s.imm.types))
   545  	if id < s.imm.firstTypeID {
   546  		return 0, fmt.Errorf("no more type IDs")
   547  	}
   548  	return id, nil
   549  }
   550  
   551  // TypeByID returns the BTF Type with the given type ID.
   552  //
   553  // Returns an error wrapping ErrNotFound if a Type with the given ID
   554  // does not exist in the Spec.
   555  func (s *Spec) TypeByID(id TypeID) (Type, error) {
   556  	typ, ok := s.typeByID(id)
   557  	if !ok {
   558  		return nil, fmt.Errorf("look up type with ID %d (first ID is %d): %w", id, s.imm.firstTypeID, ErrNotFound)
   559  	}
   560  
   561  	return typ, nil
   562  }
   563  
   564  // TypeID returns the ID for a given Type.
   565  //
   566  // Returns an error wrapping [ErrNotFound] if the type isn't part of the Spec.
   567  func (s *Spec) TypeID(typ Type) (TypeID, error) {
   568  	return s.mutableTypes.typeID(typ)
   569  }
   570  
   571  // AnyTypesByName returns a list of BTF Types with the given name.
   572  //
   573  // If the BTF blob describes multiple compilation units like vmlinux, multiple
   574  // Types with the same name and kind can exist, but might not describe the same
   575  // data structure.
   576  //
   577  // Returns an error wrapping ErrNotFound if no matching Type exists in the Spec.
   578  func (s *Spec) AnyTypesByName(name string) ([]Type, error) {
   579  	return s.mutableTypes.anyTypesByName(name)
   580  }
   581  
   582  // AnyTypeByName returns a Type with the given name.
   583  //
   584  // Returns an error if multiple types of that name exist.
   585  func (s *Spec) AnyTypeByName(name string) (Type, error) {
   586  	types, err := s.AnyTypesByName(name)
   587  	if err != nil {
   588  		return nil, err
   589  	}
   590  
   591  	if len(types) > 1 {
   592  		return nil, fmt.Errorf("found multiple types: %v", types)
   593  	}
   594  
   595  	return types[0], nil
   596  }
   597  
   598  // TypeByName searches for a Type with a specific name. Since multiple Types
   599  // with the same name can exist, the parameter typ is taken to narrow down the
   600  // search in case of a clash.
   601  //
   602  // typ must be a non-nil pointer to an implementation of a Type. On success, the
   603  // address of the found Type will be copied to typ.
   604  //
   605  // Returns an error wrapping ErrNotFound if no matching Type exists in the Spec.
   606  // Returns an error wrapping ErrMultipleTypes if multiple candidates are found.
   607  func (s *Spec) TypeByName(name string, typ interface{}) error {
   608  	typeInterface := reflect.TypeOf((*Type)(nil)).Elem()
   609  
   610  	// typ may be **T or *Type
   611  	typValue := reflect.ValueOf(typ)
   612  	if typValue.Kind() != reflect.Ptr {
   613  		return fmt.Errorf("%T is not a pointer", typ)
   614  	}
   615  
   616  	typPtr := typValue.Elem()
   617  	if !typPtr.CanSet() {
   618  		return fmt.Errorf("%T cannot be set", typ)
   619  	}
   620  
   621  	wanted := typPtr.Type()
   622  	if wanted == typeInterface {
   623  		// This is *Type. Unwrap the value's type.
   624  		wanted = typPtr.Elem().Type()
   625  	}
   626  
   627  	if !wanted.AssignableTo(typeInterface) {
   628  		return fmt.Errorf("%T does not satisfy Type interface", typ)
   629  	}
   630  
   631  	types, err := s.AnyTypesByName(name)
   632  	if err != nil {
   633  		return err
   634  	}
   635  
   636  	var candidate Type
   637  	for _, typ := range types {
   638  		if reflect.TypeOf(typ) != wanted {
   639  			continue
   640  		}
   641  
   642  		if candidate != nil {
   643  			return fmt.Errorf("type %s(%T): %w", name, typ, ErrMultipleMatches)
   644  		}
   645  
   646  		candidate = typ
   647  	}
   648  
   649  	if candidate == nil {
   650  		return fmt.Errorf("%s %s: %w", wanted, name, ErrNotFound)
   651  	}
   652  
   653  	typPtr.Set(reflect.ValueOf(candidate))
   654  
   655  	return nil
   656  }
   657  
   658  // LoadSplitSpecFromReader loads split BTF from a reader.
   659  //
   660  // Types from base are used to resolve references in the split BTF.
   661  // The returned Spec only contains types from the split BTF, not from the base.
   662  func LoadSplitSpecFromReader(r io.ReaderAt, base *Spec) (*Spec, error) {
   663  	return loadRawSpec(r, internal.NativeEndian, base)
   664  }
   665  
   666  // TypesIterator iterates over types of a given spec.
   667  type TypesIterator struct {
   668  	spec *Spec
   669  	id   TypeID
   670  	done bool
   671  	// The last visited type in the spec.
   672  	Type Type
   673  }
   674  
   675  // Iterate returns the types iterator.
   676  func (s *Spec) Iterate() *TypesIterator {
   677  	return &TypesIterator{spec: s, id: s.imm.firstTypeID}
   678  }
   679  
   680  // Next returns true as long as there are any remaining types.
   681  func (iter *TypesIterator) Next() bool {
   682  	if iter.done {
   683  		return false
   684  	}
   685  
   686  	var ok bool
   687  	iter.Type, ok = iter.spec.typeByID(iter.id)
   688  	iter.id++
   689  	iter.done = !ok
   690  	return !iter.done
   691  }