Home | History | Annotate | Download | only in dwarf
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // DWARF type information structures.
      6 // The format is heavily biased toward C, but for simplicity
      7 // the String methods use a pseudo-Go syntax.
      8 
      9 package dwarf
     10 
     11 import "strconv"
     12 
     13 // A Type conventionally represents a pointer to any of the
     14 // specific Type structures (CharType, StructType, etc.).
     15 type Type interface {
     16 	Common() *CommonType
     17 	String() string
     18 	Size() int64
     19 }
     20 
     21 // A CommonType holds fields common to multiple types.
     22 // If a field is not known or not applicable for a given type,
     23 // the zero value is used.
     24 type CommonType struct {
     25 	ByteSize int64  // size of value of this type, in bytes
     26 	Name     string // name that can be used to refer to type
     27 }
     28 
     29 func (c *CommonType) Common() *CommonType { return c }
     30 
     31 func (c *CommonType) Size() int64 { return c.ByteSize }
     32 
     33 // Basic types
     34 
     35 // A BasicType holds fields common to all basic types.
     36 type BasicType struct {
     37 	CommonType
     38 	BitSize   int64
     39 	BitOffset int64
     40 }
     41 
     42 func (b *BasicType) Basic() *BasicType { return b }
     43 
     44 func (t *BasicType) String() string {
     45 	if t.Name != "" {
     46 		return t.Name
     47 	}
     48 	return "?"
     49 }
     50 
     51 // A CharType represents a signed character type.
     52 type CharType struct {
     53 	BasicType
     54 }
     55 
     56 // A UcharType represents an unsigned character type.
     57 type UcharType struct {
     58 	BasicType
     59 }
     60 
     61 // An IntType represents a signed integer type.
     62 type IntType struct {
     63 	BasicType
     64 }
     65 
     66 // A UintType represents an unsigned integer type.
     67 type UintType struct {
     68 	BasicType
     69 }
     70 
     71 // A FloatType represents a floating point type.
     72 type FloatType struct {
     73 	BasicType
     74 }
     75 
     76 // A ComplexType represents a complex floating point type.
     77 type ComplexType struct {
     78 	BasicType
     79 }
     80 
     81 // A BoolType represents a boolean type.
     82 type BoolType struct {
     83 	BasicType
     84 }
     85 
     86 // An AddrType represents a machine address type.
     87 type AddrType struct {
     88 	BasicType
     89 }
     90 
     91 // An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type.
     92 type UnspecifiedType struct {
     93 	BasicType
     94 }
     95 
     96 // qualifiers
     97 
     98 // A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier.
     99 type QualType struct {
    100 	CommonType
    101 	Qual string
    102 	Type Type
    103 }
    104 
    105 func (t *QualType) String() string { return t.Qual + " " + t.Type.String() }
    106 
    107 func (t *QualType) Size() int64 { return t.Type.Size() }
    108 
    109 // An ArrayType represents a fixed size array type.
    110 type ArrayType struct {
    111 	CommonType
    112 	Type          Type
    113 	StrideBitSize int64 // if > 0, number of bits to hold each element
    114 	Count         int64 // if == -1, an incomplete array, like char x[].
    115 }
    116 
    117 func (t *ArrayType) String() string {
    118 	return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String()
    119 }
    120 
    121 func (t *ArrayType) Size() int64 {
    122 	if t.Count == -1 {
    123 		return 0
    124 	}
    125 	return t.Count * t.Type.Size()
    126 }
    127 
    128 // A VoidType represents the C void type.
    129 type VoidType struct {
    130 	CommonType
    131 }
    132 
    133 func (t *VoidType) String() string { return "void" }
    134 
    135 // A PtrType represents a pointer type.
    136 type PtrType struct {
    137 	CommonType
    138 	Type Type
    139 }
    140 
    141 func (t *PtrType) String() string { return "*" + t.Type.String() }
    142 
    143 // A StructType represents a struct, union, or C++ class type.
    144 type StructType struct {
    145 	CommonType
    146 	StructName string
    147 	Kind       string // "struct", "union", or "class".
    148 	Field      []*StructField
    149 	Incomplete bool // if true, struct, union, class is declared but not defined
    150 }
    151 
    152 // A StructField represents a field in a struct, union, or C++ class type.
    153 type StructField struct {
    154 	Name       string
    155 	Type       Type
    156 	ByteOffset int64
    157 	ByteSize   int64 // usually zero; use Type.Size() for normal fields
    158 	BitOffset  int64 // within the ByteSize bytes at ByteOffset
    159 	BitSize    int64 // zero if not a bit field
    160 }
    161 
    162 func (t *StructType) String() string {
    163 	if t.StructName != "" {
    164 		return t.Kind + " " + t.StructName
    165 	}
    166 	return t.Defn()
    167 }
    168 
    169 func (t *StructType) Defn() string {
    170 	s := t.Kind
    171 	if t.StructName != "" {
    172 		s += " " + t.StructName
    173 	}
    174 	if t.Incomplete {
    175 		s += " /*incomplete*/"
    176 		return s
    177 	}
    178 	s += " {"
    179 	for i, f := range t.Field {
    180 		if i > 0 {
    181 			s += "; "
    182 		}
    183 		s += f.Name + " " + f.Type.String()
    184 		s += "@" + strconv.FormatInt(f.ByteOffset, 10)
    185 		if f.BitSize > 0 {
    186 			s += " : " + strconv.FormatInt(f.BitSize, 10)
    187 			s += "@" + strconv.FormatInt(f.BitOffset, 10)
    188 		}
    189 	}
    190 	s += "}"
    191 	return s
    192 }
    193 
    194 // An EnumType represents an enumerated type.
    195 // The only indication of its native integer type is its ByteSize
    196 // (inside CommonType).
    197 type EnumType struct {
    198 	CommonType
    199 	EnumName string
    200 	Val      []*EnumValue
    201 }
    202 
    203 // An EnumValue represents a single enumeration value.
    204 type EnumValue struct {
    205 	Name string
    206 	Val  int64
    207 }
    208 
    209 func (t *EnumType) String() string {
    210 	s := "enum"
    211 	if t.EnumName != "" {
    212 		s += " " + t.EnumName
    213 	}
    214 	s += " {"
    215 	for i, v := range t.Val {
    216 		if i > 0 {
    217 			s += "; "
    218 		}
    219 		s += v.Name + "=" + strconv.FormatInt(v.Val, 10)
    220 	}
    221 	s += "}"
    222 	return s
    223 }
    224 
    225 // A FuncType represents a function type.
    226 type FuncType struct {
    227 	CommonType
    228 	ReturnType Type
    229 	ParamType  []Type
    230 }
    231 
    232 func (t *FuncType) String() string {
    233 	s := "func("
    234 	for i, t := range t.ParamType {
    235 		if i > 0 {
    236 			s += ", "
    237 		}
    238 		s += t.String()
    239 	}
    240 	s += ")"
    241 	if t.ReturnType != nil {
    242 		s += " " + t.ReturnType.String()
    243 	}
    244 	return s
    245 }
    246 
    247 // A DotDotDotType represents the variadic ... function parameter.
    248 type DotDotDotType struct {
    249 	CommonType
    250 }
    251 
    252 func (t *DotDotDotType) String() string { return "..." }
    253 
    254 // A TypedefType represents a named type.
    255 type TypedefType struct {
    256 	CommonType
    257 	Type Type
    258 }
    259 
    260 func (t *TypedefType) String() string { return t.Name }
    261 
    262 func (t *TypedefType) Size() int64 { return t.Type.Size() }
    263 
    264 // typeReader is used to read from either the info section or the
    265 // types section.
    266 type typeReader interface {
    267 	Seek(Offset)
    268 	Next() (*Entry, error)
    269 	clone() typeReader
    270 	offset() Offset
    271 	// AddressSize returns the size in bytes of addresses in the current
    272 	// compilation unit.
    273 	AddressSize() int
    274 }
    275 
    276 // Type reads the type at off in the DWARF ``info'' section.
    277 func (d *Data) Type(off Offset) (Type, error) {
    278 	return d.readType("info", d.Reader(), off, d.typeCache, nil)
    279 }
    280 
    281 // readType reads a type from r at off of name. It adds types to the
    282 // type cache, appends new typedef types to typedefs, and computes the
    283 // sizes of types. Callers should pass nil for typedefs; this is used
    284 // for internal recursion.
    285 func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, typedefs *[]*TypedefType) (Type, error) {
    286 	if t, ok := typeCache[off]; ok {
    287 		return t, nil
    288 	}
    289 	r.Seek(off)
    290 	e, err := r.Next()
    291 	if err != nil {
    292 		return nil, err
    293 	}
    294 	addressSize := r.AddressSize()
    295 	if e == nil || e.Offset != off {
    296 		return nil, DecodeError{name, off, "no type at offset"}
    297 	}
    298 
    299 	// If this is the root of the recursion, prepare to resolve
    300 	// typedef sizes once the recursion is done. This must be done
    301 	// after the type graph is constructed because it may need to
    302 	// resolve cycles in a different order than readType
    303 	// encounters them.
    304 	if typedefs == nil {
    305 		var typedefList []*TypedefType
    306 		defer func() {
    307 			for _, t := range typedefList {
    308 				t.Common().ByteSize = t.Type.Size()
    309 			}
    310 		}()
    311 		typedefs = &typedefList
    312 	}
    313 
    314 	// Parse type from Entry.
    315 	// Must always set typeCache[off] before calling
    316 	// d.readType recursively, to handle circular types correctly.
    317 	var typ Type
    318 
    319 	nextDepth := 0
    320 
    321 	// Get next child; set err if error happens.
    322 	next := func() *Entry {
    323 		if !e.Children {
    324 			return nil
    325 		}
    326 		// Only return direct children.
    327 		// Skip over composite entries that happen to be nested
    328 		// inside this one. Most DWARF generators wouldn't generate
    329 		// such a thing, but clang does.
    330 		// See golang.org/issue/6472.
    331 		for {
    332 			kid, err1 := r.Next()
    333 			if err1 != nil {
    334 				err = err1
    335 				return nil
    336 			}
    337 			if kid == nil {
    338 				err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"}
    339 				return nil
    340 			}
    341 			if kid.Tag == 0 {
    342 				if nextDepth > 0 {
    343 					nextDepth--
    344 					continue
    345 				}
    346 				return nil
    347 			}
    348 			if kid.Children {
    349 				nextDepth++
    350 			}
    351 			if nextDepth > 0 {
    352 				continue
    353 			}
    354 			return kid
    355 		}
    356 	}
    357 
    358 	// Get Type referred to by Entry's AttrType field.
    359 	// Set err if error happens. Not having a type is an error.
    360 	typeOf := func(e *Entry) Type {
    361 		tval := e.Val(AttrType)
    362 		var t Type
    363 		switch toff := tval.(type) {
    364 		case Offset:
    365 			if t, err = d.readType(name, r.clone(), toff, typeCache, typedefs); err != nil {
    366 				return nil
    367 			}
    368 		case uint64:
    369 			if t, err = d.sigToType(toff); err != nil {
    370 				return nil
    371 			}
    372 		default:
    373 			// It appears that no Type means "void".
    374 			return new(VoidType)
    375 		}
    376 		return t
    377 	}
    378 
    379 	switch e.Tag {
    380 	case TagArrayType:
    381 		// Multi-dimensional array.  (DWARF v2 5.4)
    382 		// Attributes:
    383 		//	AttrType:subtype [required]
    384 		//	AttrStrideSize: size in bits of each element of the array
    385 		//	AttrByteSize: size of entire array
    386 		// Children:
    387 		//	TagSubrangeType or TagEnumerationType giving one dimension.
    388 		//	dimensions are in left to right order.
    389 		t := new(ArrayType)
    390 		typ = t
    391 		typeCache[off] = t
    392 		if t.Type = typeOf(e); err != nil {
    393 			goto Error
    394 		}
    395 		t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
    396 
    397 		// Accumulate dimensions,
    398 		var dims []int64
    399 		for kid := next(); kid != nil; kid = next() {
    400 			// TODO(rsc): Can also be TagEnumerationType
    401 			// but haven't seen that in the wild yet.
    402 			switch kid.Tag {
    403 			case TagSubrangeType:
    404 				count, ok := kid.Val(AttrCount).(int64)
    405 				if !ok {
    406 					// Old binaries may have an upper bound instead.
    407 					count, ok = kid.Val(AttrUpperBound).(int64)
    408 					if ok {
    409 						count++ // Length is one more than upper bound.
    410 					} else if len(dims) == 0 {
    411 						count = -1 // As in x[].
    412 					}
    413 				}
    414 				dims = append(dims, count)
    415 			case TagEnumerationType:
    416 				err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"}
    417 				goto Error
    418 			}
    419 		}
    420 		if len(dims) == 0 {
    421 			// LLVM generates this for x[].
    422 			dims = []int64{-1}
    423 		}
    424 
    425 		t.Count = dims[0]
    426 		for i := len(dims) - 1; i >= 1; i-- {
    427 			t.Type = &ArrayType{Type: t.Type, Count: dims[i]}
    428 		}
    429 
    430 	case TagBaseType:
    431 		// Basic type.  (DWARF v2 5.1)
    432 		// Attributes:
    433 		//	AttrName: name of base type in programming language of the compilation unit [required]
    434 		//	AttrEncoding: encoding value for type (encFloat etc) [required]
    435 		//	AttrByteSize: size of type in bytes [required]
    436 		//	AttrBitOffset: for sub-byte types, size in bits
    437 		//	AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes
    438 		name, _ := e.Val(AttrName).(string)
    439 		enc, ok := e.Val(AttrEncoding).(int64)
    440 		if !ok {
    441 			err = DecodeError{name, e.Offset, "missing encoding attribute for " + name}
    442 			goto Error
    443 		}
    444 		switch enc {
    445 		default:
    446 			err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"}
    447 			goto Error
    448 
    449 		case encAddress:
    450 			typ = new(AddrType)
    451 		case encBoolean:
    452 			typ = new(BoolType)
    453 		case encComplexFloat:
    454 			typ = new(ComplexType)
    455 			if name == "complex" {
    456 				// clang writes out 'complex' instead of 'complex float' or 'complex double'.
    457 				// clang also writes out a byte size that we can use to distinguish.
    458 				// See issue 8694.
    459 				switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize {
    460 				case 8:
    461 					name = "complex float"
    462 				case 16:
    463 					name = "complex double"
    464 				}
    465 			}
    466 		case encFloat:
    467 			typ = new(FloatType)
    468 		case encSigned:
    469 			typ = new(IntType)
    470 		case encUnsigned:
    471 			typ = new(UintType)
    472 		case encSignedChar:
    473 			typ = new(CharType)
    474 		case encUnsignedChar:
    475 			typ = new(UcharType)
    476 		}
    477 		typeCache[off] = typ
    478 		t := typ.(interface {
    479 			Basic() *BasicType
    480 		}).Basic()
    481 		t.Name = name
    482 		t.BitSize, _ = e.Val(AttrBitSize).(int64)
    483 		t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
    484 
    485 	case TagClassType, TagStructType, TagUnionType:
    486 		// Structure, union, or class type.  (DWARF v2 5.5)
    487 		// Attributes:
    488 		//	AttrName: name of struct, union, or class
    489 		//	AttrByteSize: byte size [required]
    490 		//	AttrDeclaration: if true, struct/union/class is incomplete
    491 		// Children:
    492 		//	TagMember to describe one member.
    493 		//		AttrName: name of member [required]
    494 		//		AttrType: type of member [required]
    495 		//		AttrByteSize: size in bytes
    496 		//		AttrBitOffset: bit offset within bytes for bit fields
    497 		//		AttrBitSize: bit size for bit fields
    498 		//		AttrDataMemberLoc: location within struct [required for struct, class]
    499 		// There is much more to handle C++, all ignored for now.
    500 		t := new(StructType)
    501 		typ = t
    502 		typeCache[off] = t
    503 		switch e.Tag {
    504 		case TagClassType:
    505 			t.Kind = "class"
    506 		case TagStructType:
    507 			t.Kind = "struct"
    508 		case TagUnionType:
    509 			t.Kind = "union"
    510 		}
    511 		t.StructName, _ = e.Val(AttrName).(string)
    512 		t.Incomplete = e.Val(AttrDeclaration) != nil
    513 		t.Field = make([]*StructField, 0, 8)
    514 		var lastFieldType *Type
    515 		var lastFieldBitOffset int64
    516 		for kid := next(); kid != nil; kid = next() {
    517 			if kid.Tag != TagMember {
    518 				continue
    519 			}
    520 			f := new(StructField)
    521 			if f.Type = typeOf(kid); err != nil {
    522 				goto Error
    523 			}
    524 			switch loc := kid.Val(AttrDataMemberLoc).(type) {
    525 			case []byte:
    526 				// TODO: Should have original compilation
    527 				// unit here, not unknownFormat.
    528 				b := makeBuf(d, unknownFormat{}, "location", 0, loc)
    529 				if b.uint8() != opPlusUconst {
    530 					err = DecodeError{name, kid.Offset, "unexpected opcode"}
    531 					goto Error
    532 				}
    533 				f.ByteOffset = int64(b.uint())
    534 				if b.err != nil {
    535 					err = b.err
    536 					goto Error
    537 				}
    538 			case int64:
    539 				f.ByteOffset = loc
    540 			}
    541 
    542 			haveBitOffset := false
    543 			f.Name, _ = kid.Val(AttrName).(string)
    544 			f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
    545 			f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64)
    546 			f.BitSize, _ = kid.Val(AttrBitSize).(int64)
    547 			t.Field = append(t.Field, f)
    548 
    549 			bito := f.BitOffset
    550 			if !haveBitOffset {
    551 				bito = f.ByteOffset * 8
    552 			}
    553 			if bito == lastFieldBitOffset && t.Kind != "union" {
    554 				// Last field was zero width. Fix array length.
    555 				// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
    556 				zeroArray(lastFieldType)
    557 			}
    558 			lastFieldType = &f.Type
    559 			lastFieldBitOffset = bito
    560 		}
    561 		if t.Kind != "union" {
    562 			b, ok := e.Val(AttrByteSize).(int64)
    563 			if ok && b*8 == lastFieldBitOffset {
    564 				// Final field must be zero width. Fix array length.
    565 				zeroArray(lastFieldType)
    566 			}
    567 		}
    568 
    569 	case TagConstType, TagVolatileType, TagRestrictType:
    570 		// Type modifier (DWARF v2 5.2)
    571 		// Attributes:
    572 		//	AttrType: subtype
    573 		t := new(QualType)
    574 		typ = t
    575 		typeCache[off] = t
    576 		if t.Type = typeOf(e); err != nil {
    577 			goto Error
    578 		}
    579 		switch e.Tag {
    580 		case TagConstType:
    581 			t.Qual = "const"
    582 		case TagRestrictType:
    583 			t.Qual = "restrict"
    584 		case TagVolatileType:
    585 			t.Qual = "volatile"
    586 		}
    587 
    588 	case TagEnumerationType:
    589 		// Enumeration type (DWARF v2 5.6)
    590 		// Attributes:
    591 		//	AttrName: enum name if any
    592 		//	AttrByteSize: bytes required to represent largest value
    593 		// Children:
    594 		//	TagEnumerator:
    595 		//		AttrName: name of constant
    596 		//		AttrConstValue: value of constant
    597 		t := new(EnumType)
    598 		typ = t
    599 		typeCache[off] = t
    600 		t.EnumName, _ = e.Val(AttrName).(string)
    601 		t.Val = make([]*EnumValue, 0, 8)
    602 		for kid := next(); kid != nil; kid = next() {
    603 			if kid.Tag == TagEnumerator {
    604 				f := new(EnumValue)
    605 				f.Name, _ = kid.Val(AttrName).(string)
    606 				f.Val, _ = kid.Val(AttrConstValue).(int64)
    607 				n := len(t.Val)
    608 				if n >= cap(t.Val) {
    609 					val := make([]*EnumValue, n, n*2)
    610 					copy(val, t.Val)
    611 					t.Val = val
    612 				}
    613 				t.Val = t.Val[0 : n+1]
    614 				t.Val[n] = f
    615 			}
    616 		}
    617 
    618 	case TagPointerType:
    619 		// Type modifier (DWARF v2 5.2)
    620 		// Attributes:
    621 		//	AttrType: subtype [not required!  void* has no AttrType]
    622 		//	AttrAddrClass: address class [ignored]
    623 		t := new(PtrType)
    624 		typ = t
    625 		typeCache[off] = t
    626 		if e.Val(AttrType) == nil {
    627 			t.Type = &VoidType{}
    628 			break
    629 		}
    630 		t.Type = typeOf(e)
    631 
    632 	case TagSubroutineType:
    633 		// Subroutine type.  (DWARF v2 5.7)
    634 		// Attributes:
    635 		//	AttrType: type of return value if any
    636 		//	AttrName: possible name of type [ignored]
    637 		//	AttrPrototyped: whether used ANSI C prototype [ignored]
    638 		// Children:
    639 		//	TagFormalParameter: typed parameter
    640 		//		AttrType: type of parameter
    641 		//	TagUnspecifiedParameter: final ...
    642 		t := new(FuncType)
    643 		typ = t
    644 		typeCache[off] = t
    645 		if t.ReturnType = typeOf(e); err != nil {
    646 			goto Error
    647 		}
    648 		t.ParamType = make([]Type, 0, 8)
    649 		for kid := next(); kid != nil; kid = next() {
    650 			var tkid Type
    651 			switch kid.Tag {
    652 			default:
    653 				continue
    654 			case TagFormalParameter:
    655 				if tkid = typeOf(kid); err != nil {
    656 					goto Error
    657 				}
    658 			case TagUnspecifiedParameters:
    659 				tkid = &DotDotDotType{}
    660 			}
    661 			t.ParamType = append(t.ParamType, tkid)
    662 		}
    663 
    664 	case TagTypedef:
    665 		// Typedef (DWARF v2 5.3)
    666 		// Attributes:
    667 		//	AttrName: name [required]
    668 		//	AttrType: type definition [required]
    669 		t := new(TypedefType)
    670 		typ = t
    671 		typeCache[off] = t
    672 		t.Name, _ = e.Val(AttrName).(string)
    673 		t.Type = typeOf(e)
    674 
    675 	case TagUnspecifiedType:
    676 		// Unspecified type (DWARF v3 5.2)
    677 		// Attributes:
    678 		//	AttrName: name
    679 		t := new(UnspecifiedType)
    680 		typ = t
    681 		typeCache[off] = t
    682 		t.Name, _ = e.Val(AttrName).(string)
    683 	}
    684 
    685 	if err != nil {
    686 		goto Error
    687 	}
    688 
    689 	{
    690 		b, ok := e.Val(AttrByteSize).(int64)
    691 		if !ok {
    692 			b = -1
    693 			switch t := typ.(type) {
    694 			case *TypedefType:
    695 				// Record that we need to resolve this
    696 				// type's size once the type graph is
    697 				// constructed.
    698 				*typedefs = append(*typedefs, t)
    699 			case *PtrType:
    700 				b = int64(addressSize)
    701 			}
    702 		}
    703 		typ.Common().ByteSize = b
    704 	}
    705 	return typ, nil
    706 
    707 Error:
    708 	// If the parse fails, take the type out of the cache
    709 	// so that the next call with this offset doesn't hit
    710 	// the cache and return success.
    711 	delete(typeCache, off)
    712 	return nil, err
    713 }
    714 
    715 func zeroArray(t *Type) {
    716 	if t == nil {
    717 		return
    718 	}
    719 	at, ok := (*t).(*ArrayType)
    720 	if !ok || at.Type.Size() == 0 {
    721 		return
    722 	}
    723 	// Make a copy to avoid invalidating typeCache.
    724 	tt := *at
    725 	tt.Count = 0
    726 	*t = &tt
    727 }
    728