debug/dwarf: compute ByteSize for more DWARF types

When a size attribute is not present for a type, we can still determine
the object size in some other cases: when the type is a Typedef
referring to another type, when the type embeds a Typedef, or when the
type is a pointer and we know the default address size.

Change-Id: Ie4ae12d1b968a6b8b4e37d13ffc7b479bc69b621
Reviewed-on: https://go-review.googlesource.com/10479
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/dwarf/entry.go b/dwarf/entry.go
index 665c684..4076ec1 100644
--- a/dwarf/entry.go
+++ b/dwarf/entry.go
@@ -292,6 +292,12 @@
 	return r
 }
 
+// AddressSize returns the size in bytes of addresses in the current compilation
+// unit.
+func (r *Reader) AddressSize() int {
+	return r.d.unit[r.unit].asize
+}
+
 // Seek positions the Reader at offset off in the encoded entry stream.
 // Offset 0 can be used to denote the first entry.
 func (r *Reader) Seek(off Offset) {
diff --git a/dwarf/type.go b/dwarf/type.go
index 134231f..a2471b6 100644
--- a/dwarf/type.go
+++ b/dwarf/type.go
@@ -335,6 +335,9 @@
 	Next() (*Entry, error)
 	clone() typeReader
 	offset() Offset
+	// AddressSize returns the size in bytes of addresses in the current
+	// compilation unit.
+	AddressSize() int
 }
 
 // Type reads the type at off in the DWARF ``info'' section.
@@ -358,6 +361,7 @@
 	if err != nil {
 		return nil, err
 	}
+	addressSize := r.AddressSize()
 	if e == nil || e.Offset != off {
 		return nil, DecodeError{name, off, "no type at offset"}
 	}
@@ -796,6 +800,18 @@
 		b, ok := e.Val(AttrByteSize).(int64)
 		if !ok {
 			b = -1
+			switch t := typ.(type) {
+			case *TypedefType:
+				b = t.Type.Size()
+			case *MapType:
+				b = t.Type.Size()
+			case *ChanType:
+				b = t.Type.Size()
+			case *InterfaceType:
+				b = t.Type.Size()
+			case *PtrType:
+				b = int64(addressSize)
+			}
 		}
 		typ.Common().ByteSize = b
 	}
diff --git a/dwarf/typeunit.go b/dwarf/typeunit.go
index 3fd1c99..d93b9f5 100644
--- a/dwarf/typeunit.go
+++ b/dwarf/typeunit.go
@@ -135,6 +135,11 @@
 	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
 }
 
+// AddressSize returns the size in bytes of addresses in the current type unit.
+func (tur *typeUnitReader) AddressSize() int {
+	return tur.tu.unit.asize
+}
+
 // Next reads the next Entry from the type unit.
 func (tur *typeUnitReader) Next() (*Entry, error) {
 	if tur.err != nil {