ogle: copy debug/dwarf into our repo
We will need to make changes, so have a local copy.

LGTM=nigeltao
R=nigeltao
https://golang.org/cl/81640043
diff --git a/debug/dwarf/buf.go b/debug/dwarf/buf.go
new file mode 100644
index 0000000..53c46eb
--- /dev/null
+++ b/debug/dwarf/buf.go
@@ -0,0 +1,181 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Buffered reading and decoding of DWARF data streams.
+
+package dwarf
+
+import (
+	"encoding/binary"
+	"strconv"
+)
+
+// Data buffer being decoded.
+type buf struct {
+	dwarf  *Data
+	order  binary.ByteOrder
+	format dataFormat
+	name   string
+	off    Offset
+	data   []byte
+	err    error
+}
+
+// Data format, other than byte order.  This affects the handling of
+// certain field formats.
+type dataFormat interface {
+	// DWARF version number.  Zero means unknown.
+	version() int
+
+	// 64-bit DWARF format?
+	dwarf64() (dwarf64 bool, isKnown bool)
+
+	// Size of an address, in bytes.  Zero means unknown.
+	addrsize() int
+}
+
+// Some parts of DWARF have no data format, e.g., abbrevs.
+type unknownFormat struct{}
+
+func (u unknownFormat) version() int {
+	return 0
+}
+
+func (u unknownFormat) dwarf64() (bool, bool) {
+	return false, false
+}
+
+func (u unknownFormat) addrsize() int {
+	return 0
+}
+
+func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf {
+	return buf{d, d.order, format, name, off, data, nil}
+}
+
+func (b *buf) uint8() uint8 {
+	if len(b.data) < 1 {
+		b.error("underflow")
+		return 0
+	}
+	val := b.data[0]
+	b.data = b.data[1:]
+	b.off++
+	return val
+}
+
+func (b *buf) bytes(n int) []byte {
+	if len(b.data) < n {
+		b.error("underflow")
+		return nil
+	}
+	data := b.data[0:n]
+	b.data = b.data[n:]
+	b.off += Offset(n)
+	return data
+}
+
+func (b *buf) skip(n int) { b.bytes(n) }
+
+func (b *buf) string() string {
+	for i := 0; i < len(b.data); i++ {
+		if b.data[i] == 0 {
+			s := string(b.data[0:i])
+			b.data = b.data[i+1:]
+			b.off += Offset(i + 1)
+			return s
+		}
+	}
+	b.error("underflow")
+	return ""
+}
+
+func (b *buf) uint16() uint16 {
+	a := b.bytes(2)
+	if a == nil {
+		return 0
+	}
+	return b.order.Uint16(a)
+}
+
+func (b *buf) uint32() uint32 {
+	a := b.bytes(4)
+	if a == nil {
+		return 0
+	}
+	return b.order.Uint32(a)
+}
+
+func (b *buf) uint64() uint64 {
+	a := b.bytes(8)
+	if a == nil {
+		return 0
+	}
+	return b.order.Uint64(a)
+}
+
+// Read a varint, which is 7 bits per byte, little endian.
+// the 0x80 bit means read another byte.
+func (b *buf) varint() (c uint64, bits uint) {
+	for i := 0; i < len(b.data); i++ {
+		byte := b.data[i]
+		c |= uint64(byte&0x7F) << bits
+		bits += 7
+		if byte&0x80 == 0 {
+			b.off += Offset(i + 1)
+			b.data = b.data[i+1:]
+			return c, bits
+		}
+	}
+	return 0, 0
+}
+
+// Unsigned int is just a varint.
+func (b *buf) uint() uint64 {
+	x, _ := b.varint()
+	return x
+}
+
+// Signed int is a sign-extended varint.
+func (b *buf) int() int64 {
+	ux, bits := b.varint()
+	x := int64(ux)
+	if x&(1<<(bits-1)) != 0 {
+		x |= -1 << bits
+	}
+	return x
+}
+
+// Address-sized uint.
+func (b *buf) addr() uint64 {
+	switch b.format.addrsize() {
+	case 1:
+		return uint64(b.uint8())
+	case 2:
+		return uint64(b.uint16())
+	case 4:
+		return uint64(b.uint32())
+	case 8:
+		return uint64(b.uint64())
+	}
+	b.error("unknown address size")
+	return 0
+}
+
+func (b *buf) error(s string) {
+	if b.err == nil {
+		b.data = nil
+		b.err = DecodeError{b.name, b.off, s}
+	}
+}
+
+type DecodeError struct {
+	Name   string
+	Offset Offset
+	Err    string
+}
+
+func (e DecodeError) Error() string {
+	return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.FormatInt(int64(e.Offset), 16) + ": " + e.Err
+}
diff --git a/debug/dwarf/const.go b/debug/dwarf/const.go
new file mode 100644
index 0000000..93c6888
--- /dev/null
+++ b/debug/dwarf/const.go
@@ -0,0 +1,454 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Constants
+
+package dwarf
+
+import "strconv"
+
+// An Attr identifies the attribute type in a DWARF Entry's Field.
+type Attr uint32
+
+const (
+	AttrSibling        Attr = 0x01
+	AttrLocation       Attr = 0x02
+	AttrName           Attr = 0x03
+	AttrOrdering       Attr = 0x09
+	AttrByteSize       Attr = 0x0B
+	AttrBitOffset      Attr = 0x0C
+	AttrBitSize        Attr = 0x0D
+	AttrStmtList       Attr = 0x10
+	AttrLowpc          Attr = 0x11
+	AttrHighpc         Attr = 0x12
+	AttrLanguage       Attr = 0x13
+	AttrDiscr          Attr = 0x15
+	AttrDiscrValue     Attr = 0x16
+	AttrVisibility     Attr = 0x17
+	AttrImport         Attr = 0x18
+	AttrStringLength   Attr = 0x19
+	AttrCommonRef      Attr = 0x1A
+	AttrCompDir        Attr = 0x1B
+	AttrConstValue     Attr = 0x1C
+	AttrContainingType Attr = 0x1D
+	AttrDefaultValue   Attr = 0x1E
+	AttrInline         Attr = 0x20
+	AttrIsOptional     Attr = 0x21
+	AttrLowerBound     Attr = 0x22
+	AttrProducer       Attr = 0x25
+	AttrPrototyped     Attr = 0x27
+	AttrReturnAddr     Attr = 0x2A
+	AttrStartScope     Attr = 0x2C
+	AttrStrideSize     Attr = 0x2E
+	AttrUpperBound     Attr = 0x2F
+	AttrAbstractOrigin Attr = 0x31
+	AttrAccessibility  Attr = 0x32
+	AttrAddrClass      Attr = 0x33
+	AttrArtificial     Attr = 0x34
+	AttrBaseTypes      Attr = 0x35
+	AttrCalling        Attr = 0x36
+	AttrCount          Attr = 0x37
+	AttrDataMemberLoc  Attr = 0x38
+	AttrDeclColumn     Attr = 0x39
+	AttrDeclFile       Attr = 0x3A
+	AttrDeclLine       Attr = 0x3B
+	AttrDeclaration    Attr = 0x3C
+	AttrDiscrList      Attr = 0x3D
+	AttrEncoding       Attr = 0x3E
+	AttrExternal       Attr = 0x3F
+	AttrFrameBase      Attr = 0x40
+	AttrFriend         Attr = 0x41
+	AttrIdentifierCase Attr = 0x42
+	AttrMacroInfo      Attr = 0x43
+	AttrNamelistItem   Attr = 0x44
+	AttrPriority       Attr = 0x45
+	AttrSegment        Attr = 0x46
+	AttrSpecification  Attr = 0x47
+	AttrStaticLink     Attr = 0x48
+	AttrType           Attr = 0x49
+	AttrUseLocation    Attr = 0x4A
+	AttrVarParam       Attr = 0x4B
+	AttrVirtuality     Attr = 0x4C
+	AttrVtableElemLoc  Attr = 0x4D
+	AttrAllocated      Attr = 0x4E
+	AttrAssociated     Attr = 0x4F
+	AttrDataLocation   Attr = 0x50
+	AttrStride         Attr = 0x51
+	AttrEntrypc        Attr = 0x52
+	AttrUseUTF8        Attr = 0x53
+	AttrExtension      Attr = 0x54
+	AttrRanges         Attr = 0x55
+	AttrTrampoline     Attr = 0x56
+	AttrCallColumn     Attr = 0x57
+	AttrCallFile       Attr = 0x58
+	AttrCallLine       Attr = 0x59
+	AttrDescription    Attr = 0x5A
+)
+
+var attrNames = [...]string{
+	AttrSibling:        "Sibling",
+	AttrLocation:       "Location",
+	AttrName:           "Name",
+	AttrOrdering:       "Ordering",
+	AttrByteSize:       "ByteSize",
+	AttrBitOffset:      "BitOffset",
+	AttrBitSize:        "BitSize",
+	AttrStmtList:       "StmtList",
+	AttrLowpc:          "Lowpc",
+	AttrHighpc:         "Highpc",
+	AttrLanguage:       "Language",
+	AttrDiscr:          "Discr",
+	AttrDiscrValue:     "DiscrValue",
+	AttrVisibility:     "Visibility",
+	AttrImport:         "Import",
+	AttrStringLength:   "StringLength",
+	AttrCommonRef:      "CommonRef",
+	AttrCompDir:        "CompDir",
+	AttrConstValue:     "ConstValue",
+	AttrContainingType: "ContainingType",
+	AttrDefaultValue:   "DefaultValue",
+	AttrInline:         "Inline",
+	AttrIsOptional:     "IsOptional",
+	AttrLowerBound:     "LowerBound",
+	AttrProducer:       "Producer",
+	AttrPrototyped:     "Prototyped",
+	AttrReturnAddr:     "ReturnAddr",
+	AttrStartScope:     "StartScope",
+	AttrStrideSize:     "StrideSize",
+	AttrUpperBound:     "UpperBound",
+	AttrAbstractOrigin: "AbstractOrigin",
+	AttrAccessibility:  "Accessibility",
+	AttrAddrClass:      "AddrClass",
+	AttrArtificial:     "Artificial",
+	AttrBaseTypes:      "BaseTypes",
+	AttrCalling:        "Calling",
+	AttrCount:          "Count",
+	AttrDataMemberLoc:  "DataMemberLoc",
+	AttrDeclColumn:     "DeclColumn",
+	AttrDeclFile:       "DeclFile",
+	AttrDeclLine:       "DeclLine",
+	AttrDeclaration:    "Declaration",
+	AttrDiscrList:      "DiscrList",
+	AttrEncoding:       "Encoding",
+	AttrExternal:       "External",
+	AttrFrameBase:      "FrameBase",
+	AttrFriend:         "Friend",
+	AttrIdentifierCase: "IdentifierCase",
+	AttrMacroInfo:      "MacroInfo",
+	AttrNamelistItem:   "NamelistItem",
+	AttrPriority:       "Priority",
+	AttrSegment:        "Segment",
+	AttrSpecification:  "Specification",
+	AttrStaticLink:     "StaticLink",
+	AttrType:           "Type",
+	AttrUseLocation:    "UseLocation",
+	AttrVarParam:       "VarParam",
+	AttrVirtuality:     "Virtuality",
+	AttrVtableElemLoc:  "VtableElemLoc",
+	AttrAllocated:      "Allocated",
+	AttrAssociated:     "Associated",
+	AttrDataLocation:   "DataLocation",
+	AttrStride:         "Stride",
+	AttrEntrypc:        "Entrypc",
+	AttrUseUTF8:        "UseUTF8",
+	AttrExtension:      "Extension",
+	AttrRanges:         "Ranges",
+	AttrTrampoline:     "Trampoline",
+	AttrCallColumn:     "CallColumn",
+	AttrCallFile:       "CallFile",
+	AttrCallLine:       "CallLine",
+	AttrDescription:    "Description",
+}
+
+func (a Attr) String() string {
+	if int(a) < len(attrNames) {
+		s := attrNames[a]
+		if s != "" {
+			return s
+		}
+	}
+	return strconv.Itoa(int(a))
+}
+
+func (a Attr) GoString() string {
+	if int(a) < len(attrNames) {
+		s := attrNames[a]
+		if s != "" {
+			return "dwarf.Attr" + s
+		}
+	}
+	return "dwarf.Attr(" + strconv.FormatInt(int64(a), 10) + ")"
+}
+
+// A format is a DWARF data encoding format.
+type format uint32
+
+const (
+	// value formats
+	formAddr        format = 0x01
+	formDwarfBlock2 format = 0x03
+	formDwarfBlock4 format = 0x04
+	formData2       format = 0x05
+	formData4       format = 0x06
+	formData8       format = 0x07
+	formString      format = 0x08
+	formDwarfBlock  format = 0x09
+	formDwarfBlock1 format = 0x0A
+	formData1       format = 0x0B
+	formFlag        format = 0x0C
+	formSdata       format = 0x0D
+	formStrp        format = 0x0E
+	formUdata       format = 0x0F
+	formRefAddr     format = 0x10
+	formRef1        format = 0x11
+	formRef2        format = 0x12
+	formRef4        format = 0x13
+	formRef8        format = 0x14
+	formRefUdata    format = 0x15
+	formIndirect    format = 0x16
+	// The following are new in DWARF 4.
+	formSecOffset   format = 0x17
+	formExprloc     format = 0x18
+	formFlagPresent format = 0x19
+	formRefSig8     format = 0x20
+	// Extensions for multi-file compression (.dwz)
+	// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
+	formGnuRefAlt  format = 0x1f20
+	formGnuStrpAlt format = 0x1f21
+)
+
+// A Tag is the classification (the type) of an Entry.
+type Tag uint32
+
+const (
+	TagArrayType              Tag = 0x01
+	TagClassType              Tag = 0x02
+	TagEntryPoint             Tag = 0x03
+	TagEnumerationType        Tag = 0x04
+	TagFormalParameter        Tag = 0x05
+	TagImportedDeclaration    Tag = 0x08
+	TagLabel                  Tag = 0x0A
+	TagLexDwarfBlock          Tag = 0x0B
+	TagMember                 Tag = 0x0D
+	TagPointerType            Tag = 0x0F
+	TagReferenceType          Tag = 0x10
+	TagCompileUnit            Tag = 0x11
+	TagStringType             Tag = 0x12
+	TagStructType             Tag = 0x13
+	TagSubroutineType         Tag = 0x15
+	TagTypedef                Tag = 0x16
+	TagUnionType              Tag = 0x17
+	TagUnspecifiedParameters  Tag = 0x18
+	TagVariant                Tag = 0x19
+	TagCommonDwarfBlock       Tag = 0x1A
+	TagCommonInclusion        Tag = 0x1B
+	TagInheritance            Tag = 0x1C
+	TagInlinedSubroutine      Tag = 0x1D
+	TagModule                 Tag = 0x1E
+	TagPtrToMemberType        Tag = 0x1F
+	TagSetType                Tag = 0x20
+	TagSubrangeType           Tag = 0x21
+	TagWithStmt               Tag = 0x22
+	TagAccessDeclaration      Tag = 0x23
+	TagBaseType               Tag = 0x24
+	TagCatchDwarfBlock        Tag = 0x25
+	TagConstType              Tag = 0x26
+	TagConstant               Tag = 0x27
+	TagEnumerator             Tag = 0x28
+	TagFileType               Tag = 0x29
+	TagFriend                 Tag = 0x2A
+	TagNamelist               Tag = 0x2B
+	TagNamelistItem           Tag = 0x2C
+	TagPackedType             Tag = 0x2D
+	TagSubprogram             Tag = 0x2E
+	TagTemplateTypeParameter  Tag = 0x2F
+	TagTemplateValueParameter Tag = 0x30
+	TagThrownType             Tag = 0x31
+	TagTryDwarfBlock          Tag = 0x32
+	TagVariantPart            Tag = 0x33
+	TagVariable               Tag = 0x34
+	TagVolatileType           Tag = 0x35
+	// The following are new in DWARF 3.
+	TagDwarfProcedure  Tag = 0x36
+	TagRestrictType    Tag = 0x37
+	TagInterfaceType   Tag = 0x38
+	TagNamespace       Tag = 0x39
+	TagImportedModule  Tag = 0x3A
+	TagUnspecifiedType Tag = 0x3B
+	TagPartialUnit     Tag = 0x3C
+	TagImportedUnit    Tag = 0x3D
+	TagMutableType     Tag = 0x3E // Later removed from DWARF.
+	TagCondition       Tag = 0x3F
+	TagSharedType      Tag = 0x40
+	// The following are new in DWARF 4.
+	TagTypeUnit            Tag = 0x41
+	TagRvalueReferenceType Tag = 0x42
+	TagTemplateAlias       Tag = 0x43
+)
+
+var tagNames = [...]string{
+	TagArrayType:              "ArrayType",
+	TagClassType:              "ClassType",
+	TagEntryPoint:             "EntryPoint",
+	TagEnumerationType:        "EnumerationType",
+	TagFormalParameter:        "FormalParameter",
+	TagImportedDeclaration:    "ImportedDeclaration",
+	TagLabel:                  "Label",
+	TagLexDwarfBlock:          "LexDwarfBlock",
+	TagMember:                 "Member",
+	TagPointerType:            "PointerType",
+	TagReferenceType:          "ReferenceType",
+	TagCompileUnit:            "CompileUnit",
+	TagStringType:             "StringType",
+	TagStructType:             "StructType",
+	TagSubroutineType:         "SubroutineType",
+	TagTypedef:                "Typedef",
+	TagUnionType:              "UnionType",
+	TagUnspecifiedParameters:  "UnspecifiedParameters",
+	TagVariant:                "Variant",
+	TagCommonDwarfBlock:       "CommonDwarfBlock",
+	TagCommonInclusion:        "CommonInclusion",
+	TagInheritance:            "Inheritance",
+	TagInlinedSubroutine:      "InlinedSubroutine",
+	TagModule:                 "Module",
+	TagPtrToMemberType:        "PtrToMemberType",
+	TagSetType:                "SetType",
+	TagSubrangeType:           "SubrangeType",
+	TagWithStmt:               "WithStmt",
+	TagAccessDeclaration:      "AccessDeclaration",
+	TagBaseType:               "BaseType",
+	TagCatchDwarfBlock:        "CatchDwarfBlock",
+	TagConstType:              "ConstType",
+	TagConstant:               "Constant",
+	TagEnumerator:             "Enumerator",
+	TagFileType:               "FileType",
+	TagFriend:                 "Friend",
+	TagNamelist:               "Namelist",
+	TagNamelistItem:           "NamelistItem",
+	TagPackedType:             "PackedType",
+	TagSubprogram:             "Subprogram",
+	TagTemplateTypeParameter:  "TemplateTypeParameter",
+	TagTemplateValueParameter: "TemplateValueParameter",
+	TagThrownType:             "ThrownType",
+	TagTryDwarfBlock:          "TryDwarfBlock",
+	TagVariantPart:            "VariantPart",
+	TagVariable:               "Variable",
+	TagVolatileType:           "VolatileType",
+	TagDwarfProcedure:         "DwarfProcedure",
+	TagRestrictType:           "RestrictType",
+	TagInterfaceType:          "InterfaceType",
+	TagNamespace:              "Namespace",
+	TagImportedModule:         "ImportedModule",
+	TagUnspecifiedType:        "UnspecifiedType",
+	TagPartialUnit:            "PartialUnit",
+	TagImportedUnit:           "ImportedUnit",
+	TagMutableType:            "MutableType",
+	TagCondition:              "Condition",
+	TagSharedType:             "SharedType",
+	TagTypeUnit:               "TypeUnit",
+	TagRvalueReferenceType:    "RvalueReferenceType",
+	TagTemplateAlias:          "TemplateAlias",
+}
+
+func (t Tag) String() string {
+	if int(t) < len(tagNames) {
+		s := tagNames[t]
+		if s != "" {
+			return s
+		}
+	}
+	return strconv.Itoa(int(t))
+}
+
+func (t Tag) GoString() string {
+	if int(t) < len(tagNames) {
+		s := tagNames[t]
+		if s != "" {
+			return "dwarf.Tag" + s
+		}
+	}
+	return "dwarf.Tag(" + strconv.FormatInt(int64(t), 10) + ")"
+}
+
+// Location expression operators.
+// The debug info encodes value locations like 8(R3)
+// as a sequence of these op codes.
+// This package does not implement full expressions;
+// the opPlusUconst operator is expected by the type parser.
+const (
+	opAddr       = 0x03 /* 1 op, const addr */
+	opDeref      = 0x06
+	opConst1u    = 0x08 /* 1 op, 1 byte const */
+	opConst1s    = 0x09 /*	" signed */
+	opConst2u    = 0x0A /* 1 op, 2 byte const  */
+	opConst2s    = 0x0B /*	" signed */
+	opConst4u    = 0x0C /* 1 op, 4 byte const */
+	opConst4s    = 0x0D /*	" signed */
+	opConst8u    = 0x0E /* 1 op, 8 byte const */
+	opConst8s    = 0x0F /*	" signed */
+	opConstu     = 0x10 /* 1 op, LEB128 const */
+	opConsts     = 0x11 /*	" signed */
+	opDup        = 0x12
+	opDrop       = 0x13
+	opOver       = 0x14
+	opPick       = 0x15 /* 1 op, 1 byte stack index */
+	opSwap       = 0x16
+	opRot        = 0x17
+	opXderef     = 0x18
+	opAbs        = 0x19
+	opAnd        = 0x1A
+	opDiv        = 0x1B
+	opMinus      = 0x1C
+	opMod        = 0x1D
+	opMul        = 0x1E
+	opNeg        = 0x1F
+	opNot        = 0x20
+	opOr         = 0x21
+	opPlus       = 0x22
+	opPlusUconst = 0x23 /* 1 op, ULEB128 addend */
+	opShl        = 0x24
+	opShr        = 0x25
+	opShra       = 0x26
+	opXor        = 0x27
+	opSkip       = 0x2F /* 1 op, signed 2-byte constant */
+	opBra        = 0x28 /* 1 op, signed 2-byte constant */
+	opEq         = 0x29
+	opGe         = 0x2A
+	opGt         = 0x2B
+	opLe         = 0x2C
+	opLt         = 0x2D
+	opNe         = 0x2E
+	opLit0       = 0x30
+	/* OpLitN = OpLit0 + N for N = 0..31 */
+	opReg0 = 0x50
+	/* OpRegN = OpReg0 + N for N = 0..31 */
+	opBreg0 = 0x70 /* 1 op, signed LEB128 constant */
+	/* OpBregN = OpBreg0 + N for N = 0..31 */
+	opRegx       = 0x90 /* 1 op, ULEB128 register */
+	opFbreg      = 0x91 /* 1 op, SLEB128 offset */
+	opBregx      = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */
+	opPiece      = 0x93 /* 1 op, ULEB128 size of piece */
+	opDerefSize  = 0x94 /* 1-byte size of data retrieved */
+	opXderefSize = 0x95 /* 1-byte size of data retrieved */
+	opNop        = 0x96
+	/* next four new in Dwarf v3 */
+	opPushObjAddr = 0x97
+	opCall2       = 0x98 /* 2-byte offset of DIE */
+	opCall4       = 0x99 /* 4-byte offset of DIE */
+	opCallRef     = 0x9A /* 4- or 8- byte offset of DIE */
+	/* 0xE0-0xFF reserved for user-specific */
+)
+
+// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry.
+const (
+	encAddress        = 0x01
+	encBoolean        = 0x02
+	encComplexFloat   = 0x03
+	encFloat          = 0x04
+	encSigned         = 0x05
+	encSignedChar     = 0x06
+	encUnsigned       = 0x07
+	encUnsignedChar   = 0x08
+	encImaginaryFloat = 0x09
+)
diff --git a/debug/dwarf/entry.go b/debug/dwarf/entry.go
new file mode 100644
index 0000000..665c684
--- /dev/null
+++ b/debug/dwarf/entry.go
@@ -0,0 +1,401 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DWARF debug information entry parser.
+// An entry is a sequence of data items of a given format.
+// The first word in the entry is an index into what DWARF
+// calls the ``abbreviation table.''  An abbreviation is really
+// just a type descriptor: it's an array of attribute tag/value format pairs.
+
+package dwarf
+
+import (
+	"errors"
+	"strconv"
+)
+
+// a single entry's description: a sequence of attributes
+type abbrev struct {
+	tag      Tag
+	children bool
+	field    []afield
+}
+
+type afield struct {
+	attr Attr
+	fmt  format
+}
+
+// a map from entry format ids to their descriptions
+type abbrevTable map[uint32]abbrev
+
+// ParseAbbrev returns the abbreviation table that starts at byte off
+// in the .debug_abbrev section.
+func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
+	if m, ok := d.abbrevCache[off]; ok {
+		return m, nil
+	}
+
+	data := d.abbrev
+	if off > uint32(len(data)) {
+		data = nil
+	} else {
+		data = data[off:]
+	}
+	b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
+
+	// Error handling is simplified by the buf getters
+	// returning an endless stream of 0s after an error.
+	m := make(abbrevTable)
+	for {
+		// Table ends with id == 0.
+		id := uint32(b.uint())
+		if id == 0 {
+			break
+		}
+
+		// Walk over attributes, counting.
+		n := 0
+		b1 := b // Read from copy of b.
+		b1.uint()
+		b1.uint8()
+		for {
+			tag := b1.uint()
+			fmt := b1.uint()
+			if tag == 0 && fmt == 0 {
+				break
+			}
+			n++
+		}
+		if b1.err != nil {
+			return nil, b1.err
+		}
+
+		// Walk over attributes again, this time writing them down.
+		var a abbrev
+		a.tag = Tag(b.uint())
+		a.children = b.uint8() != 0
+		a.field = make([]afield, n)
+		for i := range a.field {
+			a.field[i].attr = Attr(b.uint())
+			a.field[i].fmt = format(b.uint())
+		}
+		b.uint()
+		b.uint()
+
+		m[id] = a
+	}
+	if b.err != nil {
+		return nil, b.err
+	}
+	d.abbrevCache[off] = m
+	return m, nil
+}
+
+// An entry is a sequence of attribute/value pairs.
+type Entry struct {
+	Offset   Offset // offset of Entry in DWARF info
+	Tag      Tag    // tag (kind of Entry)
+	Children bool   // whether Entry is followed by children
+	Field    []Field
+}
+
+// A Field is a single attribute/value pair in an Entry.
+type Field struct {
+	Attr Attr
+	Val  interface{}
+}
+
+// Val returns the value associated with attribute Attr in Entry,
+// or nil if there is no such attribute.
+//
+// A common idiom is to merge the check for nil return with
+// the check that the value has the expected dynamic type, as in:
+//	v, ok := e.Val(AttrSibling).(int64);
+//
+func (e *Entry) Val(a Attr) interface{} {
+	for _, f := range e.Field {
+		if f.Attr == a {
+			return f.Val
+		}
+	}
+	return nil
+}
+
+// An Offset represents the location of an Entry within the DWARF info.
+// (See Reader.Seek.)
+type Offset uint32
+
+// Entry reads a single entry from buf, decoding
+// according to the given abbreviation table.
+func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
+	off := b.off
+	id := uint32(b.uint())
+	if id == 0 {
+		return &Entry{}
+	}
+	a, ok := atab[id]
+	if !ok {
+		b.error("unknown abbreviation table index")
+		return nil
+	}
+	e := &Entry{
+		Offset:   off,
+		Tag:      a.tag,
+		Children: a.children,
+		Field:    make([]Field, len(a.field)),
+	}
+	for i := range e.Field {
+		e.Field[i].Attr = a.field[i].attr
+		fmt := a.field[i].fmt
+		if fmt == formIndirect {
+			fmt = format(b.uint())
+		}
+		var val interface{}
+		switch fmt {
+		default:
+			b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16))
+
+		// address
+		case formAddr:
+			val = b.addr()
+
+		// block
+		case formDwarfBlock1:
+			val = b.bytes(int(b.uint8()))
+		case formDwarfBlock2:
+			val = b.bytes(int(b.uint16()))
+		case formDwarfBlock4:
+			val = b.bytes(int(b.uint32()))
+		case formDwarfBlock:
+			val = b.bytes(int(b.uint()))
+
+		// constant
+		case formData1:
+			val = int64(b.uint8())
+		case formData2:
+			val = int64(b.uint16())
+		case formData4:
+			val = int64(b.uint32())
+		case formData8:
+			val = int64(b.uint64())
+		case formSdata:
+			val = int64(b.int())
+		case formUdata:
+			val = int64(b.uint())
+
+		// flag
+		case formFlag:
+			val = b.uint8() == 1
+		// New in DWARF 4.
+		case formFlagPresent:
+			// The attribute is implicitly indicated as present, and no value is
+			// encoded in the debugging information entry itself.
+			val = true
+
+		// reference to other entry
+		case formRefAddr:
+			vers := b.format.version()
+			if vers == 0 {
+				b.error("unknown version for DW_FORM_ref_addr")
+			} else if vers == 2 {
+				val = Offset(b.addr())
+			} else {
+				is64, known := b.format.dwarf64()
+				if !known {
+					b.error("unknown size for DW_FORM_ref_addr")
+				} else if is64 {
+					val = Offset(b.uint64())
+				} else {
+					val = Offset(b.uint32())
+				}
+			}
+		case formRef1:
+			val = Offset(b.uint8()) + ubase
+		case formRef2:
+			val = Offset(b.uint16()) + ubase
+		case formRef4:
+			val = Offset(b.uint32()) + ubase
+		case formRef8:
+			val = Offset(b.uint64()) + ubase
+		case formRefUdata:
+			val = Offset(b.uint()) + ubase
+
+		// string
+		case formString:
+			val = b.string()
+		case formStrp:
+			off := b.uint32() // offset into .debug_str
+			if b.err != nil {
+				return nil
+			}
+			b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
+			b1.skip(int(off))
+			val = b1.string()
+			if b1.err != nil {
+				b.err = b1.err
+				return nil
+			}
+
+		// lineptr, loclistptr, macptr, rangelistptr
+		// New in DWARF 4, but clang can generate them with -gdwarf-2.
+		// Section reference, replacing use of formData4 and formData8.
+		case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
+			is64, known := b.format.dwarf64()
+			if !known {
+				b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
+			} else if is64 {
+				val = int64(b.uint64())
+			} else {
+				val = int64(b.uint32())
+			}
+
+		// exprloc
+		// New in DWARF 4.
+		case formExprloc:
+			val = b.bytes(int(b.uint()))
+
+		// reference
+		// New in DWARF 4.
+		case formRefSig8:
+			// 64-bit type signature.
+			val = b.uint64()
+		}
+		e.Field[i].Val = val
+	}
+	if b.err != nil {
+		return nil
+	}
+	return e
+}
+
+// A Reader allows reading Entry structures from a DWARF ``info'' section.
+// The Entry structures are arranged in a tree.  The Reader's Next function
+// return successive entries from a pre-order traversal of the tree.
+// If an entry has children, its Children field will be true, and the children
+// follow, terminated by an Entry with Tag 0.
+type Reader struct {
+	b            buf
+	d            *Data
+	err          error
+	unit         int
+	lastChildren bool   // .Children of last entry returned by Next
+	lastSibling  Offset // .Val(AttrSibling) of last entry returned by Next
+}
+
+// Reader returns a new Reader for Data.
+// The reader is positioned at byte offset 0 in the DWARF ``info'' section.
+func (d *Data) Reader() *Reader {
+	r := &Reader{d: d}
+	r.Seek(0)
+	return r
+}
+
+// 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) {
+	d := r.d
+	r.err = nil
+	r.lastChildren = false
+	if off == 0 {
+		if len(d.unit) == 0 {
+			return
+		}
+		u := &d.unit[0]
+		r.unit = 0
+		r.b = makeBuf(r.d, u, "info", u.off, u.data)
+		return
+	}
+
+	// TODO(rsc): binary search (maybe a new package)
+	var i int
+	var u *unit
+	for i = range d.unit {
+		u = &d.unit[i]
+		if u.off <= off && off < u.off+Offset(len(u.data)) {
+			r.unit = i
+			r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
+			return
+		}
+	}
+	r.err = errors.New("offset out of range")
+}
+
+// maybeNextUnit advances to the next unit if this one is finished.
+func (r *Reader) maybeNextUnit() {
+	for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
+		r.unit++
+		u := &r.d.unit[r.unit]
+		r.b = makeBuf(r.d, u, "info", u.off, u.data)
+	}
+}
+
+// Next reads the next entry from the encoded entry stream.
+// It returns nil, nil when it reaches the end of the section.
+// It returns an error if the current offset is invalid or the data at the
+// offset cannot be decoded as a valid Entry.
+func (r *Reader) Next() (*Entry, error) {
+	if r.err != nil {
+		return nil, r.err
+	}
+	r.maybeNextUnit()
+	if len(r.b.data) == 0 {
+		return nil, nil
+	}
+	u := &r.d.unit[r.unit]
+	e := r.b.entry(u.atable, u.base)
+	if r.b.err != nil {
+		r.err = r.b.err
+		return nil, r.err
+	}
+	if e != nil {
+		r.lastChildren = e.Children
+		if r.lastChildren {
+			r.lastSibling, _ = e.Val(AttrSibling).(Offset)
+		}
+	} else {
+		r.lastChildren = false
+	}
+	return e, nil
+}
+
+// SkipChildren skips over the child entries associated with
+// the last Entry returned by Next.  If that Entry did not have
+// children or Next has not been called, SkipChildren is a no-op.
+func (r *Reader) SkipChildren() {
+	if r.err != nil || !r.lastChildren {
+		return
+	}
+
+	// If the last entry had a sibling attribute,
+	// that attribute gives the offset of the next
+	// sibling, so we can avoid decoding the
+	// child subtrees.
+	if r.lastSibling >= r.b.off {
+		r.Seek(r.lastSibling)
+		return
+	}
+
+	for {
+		e, err := r.Next()
+		if err != nil || e == nil || e.Tag == 0 {
+			break
+		}
+		if e.Children {
+			r.SkipChildren()
+		}
+	}
+}
+
+// clone returns a copy of the reader.  This is used by the typeReader
+// interface.
+func (r *Reader) clone() typeReader {
+	return r.d.Reader()
+}
+
+// offset returns the current buffer offset.  This is used by the
+// typeReader interface.
+func (r *Reader) offset() Offset {
+	return r.b.off
+}
diff --git a/debug/dwarf/open.go b/debug/dwarf/open.go
new file mode 100644
index 0000000..c1b3f37
--- /dev/null
+++ b/debug/dwarf/open.go
@@ -0,0 +1,87 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dwarf provides access to DWARF debugging information loaded from
+// executable files, as defined in the DWARF 2.0 Standard at
+// http://dwarfstd.org/doc/dwarf-2.0.0.pdf
+package dwarf
+
+import "encoding/binary"
+
+// Data represents the DWARF debugging information
+// loaded from an executable file (for example, an ELF or Mach-O executable).
+type Data struct {
+	// raw data
+	abbrev   []byte
+	aranges  []byte
+	frame    []byte
+	info     []byte
+	line     []byte
+	pubnames []byte
+	ranges   []byte
+	str      []byte
+
+	// parsed data
+	abbrevCache map[uint32]abbrevTable
+	order       binary.ByteOrder
+	typeCache   map[Offset]Type
+	typeSigs    map[uint64]*typeUnit
+	unit        []unit
+}
+
+// New returns a new Data object initialized from the given parameters.
+// Rather than calling this function directly, clients should typically use
+// the DWARF method of the File type of the appropriate package debug/elf,
+// debug/macho, or debug/pe.
+//
+// The []byte arguments are the data from the corresponding debug section
+// in the object file; for example, for an ELF object, abbrev is the contents of
+// the ".debug_abbrev" section.
+func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) {
+	d := &Data{
+		abbrev:      abbrev,
+		aranges:     aranges,
+		frame:       frame,
+		info:        info,
+		line:        line,
+		pubnames:    pubnames,
+		ranges:      ranges,
+		str:         str,
+		abbrevCache: make(map[uint32]abbrevTable),
+		typeCache:   make(map[Offset]Type),
+		typeSigs:    make(map[uint64]*typeUnit),
+	}
+
+	// Sniff .debug_info to figure out byte order.
+	// bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
+	if len(d.info) < 6 {
+		return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
+	}
+	x, y := d.info[4], d.info[5]
+	switch {
+	case x == 0 && y == 0:
+		return nil, DecodeError{"info", 4, "unsupported version 0"}
+	case x == 0:
+		d.order = binary.BigEndian
+	case y == 0:
+		d.order = binary.LittleEndian
+	default:
+		return nil, DecodeError{"info", 4, "cannot determine byte order"}
+	}
+
+	u, err := d.parseUnits()
+	if err != nil {
+		return nil, err
+	}
+	d.unit = u
+	return d, nil
+}
+
+// AddTypes will add one .debug_types section to the DWARF data.  A
+// typical object with DWARF version 4 debug info will have multiple
+// .debug_types sections.  The name is used for error reporting only,
+// and serves to distinguish one .debug_types section from another.
+func (d *Data) AddTypes(name string, types []byte) error {
+	return d.parseTypes(name, types)
+}
diff --git a/debug/dwarf/testdata/typedef.c b/debug/dwarf/testdata/typedef.c
new file mode 100644
index 0000000..f05f015
--- /dev/null
+++ b/debug/dwarf/testdata/typedef.c
@@ -0,0 +1,85 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Linux ELF:
+gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o
+
+OS X Mach-O:
+gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho
+*/
+#include <complex.h>
+
+typedef volatile int* t_ptr_volatile_int;
+typedef const char *t_ptr_const_char;
+typedef long t_long;
+typedef unsigned short t_ushort;
+typedef int t_func_int_of_float_double(float, double);
+typedef int (*t_ptr_func_int_of_float_double)(float, double);
+typedef int (*t_ptr_func_int_of_float_complex)(float complex);
+typedef int (*t_ptr_func_int_of_double_complex)(double complex);
+typedef int (*t_ptr_func_int_of_long_double_complex)(long double complex);
+typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char);
+typedef void t_func_void_of_char(char);
+typedef void t_func_void_of_void(void);
+typedef void t_func_void_of_ptr_char_dots(char*, ...);
+typedef struct my_struct {
+	volatile int vi;
+	char x : 1;
+	int y : 4;
+	int z[0];
+	long long array[40];
+	int zz[0];
+} t_my_struct;
+typedef struct my_struct1 {
+	int zz [1];
+} t_my_struct1;
+typedef union my_union {
+	volatile int vi;
+	char x : 1;
+	int y : 4;
+	long long array[40];
+} t_my_union;
+typedef enum my_enum {
+	e1 = 1,
+	e2 = 2,
+	e3 = -5,
+	e4 = 1000000000000000LL,
+} t_my_enum;
+
+typedef struct list t_my_list;
+struct list {
+	short val;
+	t_my_list *next;
+};
+
+typedef struct tree {
+	struct tree *left, *right;
+	unsigned long long val;
+} t_my_tree;
+
+t_ptr_volatile_int *a2;
+t_ptr_const_char **a3a;
+t_long *a4;
+t_ushort *a5;
+t_func_int_of_float_double *a6;
+t_ptr_func_int_of_float_double *a7;
+t_func_ptr_int_of_char_schar_uchar *a8;
+t_func_void_of_char *a9;
+t_func_void_of_void *a10;
+t_func_void_of_ptr_char_dots *a11;
+t_my_struct *a12;
+t_my_struct1 *a12a;
+t_my_union *a12b;
+t_my_enum *a13;
+t_my_list *a14;
+t_my_tree *a15;
+t_ptr_func_int_of_float_complex *a16;
+t_ptr_func_int_of_double_complex *a17;
+t_ptr_func_int_of_long_double_complex *a18;
+
+int main()
+{
+	return 0;
+}
diff --git a/debug/dwarf/testdata/typedef.elf b/debug/dwarf/testdata/typedef.elf
new file mode 100755
index 0000000..b2062d2
--- /dev/null
+++ b/debug/dwarf/testdata/typedef.elf
Binary files differ
diff --git a/debug/dwarf/testdata/typedef.elf4 b/debug/dwarf/testdata/typedef.elf4
new file mode 100644
index 0000000..3d5a5a1
--- /dev/null
+++ b/debug/dwarf/testdata/typedef.elf4
Binary files differ
diff --git a/debug/dwarf/testdata/typedef.macho b/debug/dwarf/testdata/typedef.macho
new file mode 100644
index 0000000..f75afcc
--- /dev/null
+++ b/debug/dwarf/testdata/typedef.macho
Binary files differ
diff --git a/debug/dwarf/type.go b/debug/dwarf/type.go
new file mode 100644
index 0000000..68866d0
--- /dev/null
+++ b/debug/dwarf/type.go
@@ -0,0 +1,659 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DWARF type information structures.
+// The format is heavily biased toward C, but for simplicity
+// the String methods use a pseudo-Go syntax.
+
+package dwarf
+
+import "strconv"
+
+// A Type conventionally represents a pointer to any of the
+// specific Type structures (CharType, StructType, etc.).
+type Type interface {
+	Common() *CommonType
+	String() string
+	Size() int64
+}
+
+// A CommonType holds fields common to multiple types.
+// If a field is not known or not applicable for a given type,
+// the zero value is used.
+type CommonType struct {
+	ByteSize int64  // size of value of this type, in bytes
+	Name     string // name that can be used to refer to type
+}
+
+func (c *CommonType) Common() *CommonType { return c }
+
+func (c *CommonType) Size() int64 { return c.ByteSize }
+
+// Basic types
+
+// A BasicType holds fields common to all basic types.
+type BasicType struct {
+	CommonType
+	BitSize   int64
+	BitOffset int64
+}
+
+func (b *BasicType) Basic() *BasicType { return b }
+
+func (t *BasicType) String() string {
+	if t.Name != "" {
+		return t.Name
+	}
+	return "?"
+}
+
+// A CharType represents a signed character type.
+type CharType struct {
+	BasicType
+}
+
+// A UcharType represents an unsigned character type.
+type UcharType struct {
+	BasicType
+}
+
+// An IntType represents a signed integer type.
+type IntType struct {
+	BasicType
+}
+
+// A UintType represents an unsigned integer type.
+type UintType struct {
+	BasicType
+}
+
+// A FloatType represents a floating point type.
+type FloatType struct {
+	BasicType
+}
+
+// A ComplexType represents a complex floating point type.
+type ComplexType struct {
+	BasicType
+}
+
+// A BoolType represents a boolean type.
+type BoolType struct {
+	BasicType
+}
+
+// An AddrType represents a machine address type.
+type AddrType struct {
+	BasicType
+}
+
+// qualifiers
+
+// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier.
+type QualType struct {
+	CommonType
+	Qual string
+	Type Type
+}
+
+func (t *QualType) String() string { return t.Qual + " " + t.Type.String() }
+
+func (t *QualType) Size() int64 { return t.Type.Size() }
+
+// An ArrayType represents a fixed size array type.
+type ArrayType struct {
+	CommonType
+	Type          Type
+	StrideBitSize int64 // if > 0, number of bits to hold each element
+	Count         int64 // if == -1, an incomplete array, like char x[].
+}
+
+func (t *ArrayType) String() string {
+	return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String()
+}
+
+func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() }
+
+// A VoidType represents the C void type.
+type VoidType struct {
+	CommonType
+}
+
+func (t *VoidType) String() string { return "void" }
+
+// A PtrType represents a pointer type.
+type PtrType struct {
+	CommonType
+	Type Type
+}
+
+func (t *PtrType) String() string { return "*" + t.Type.String() }
+
+// A StructType represents a struct, union, or C++ class type.
+type StructType struct {
+	CommonType
+	StructName string
+	Kind       string // "struct", "union", or "class".
+	Field      []*StructField
+	Incomplete bool // if true, struct, union, class is declared but not defined
+}
+
+// A StructField represents a field in a struct, union, or C++ class type.
+type StructField struct {
+	Name       string
+	Type       Type
+	ByteOffset int64
+	ByteSize   int64
+	BitOffset  int64 // within the ByteSize bytes at ByteOffset
+	BitSize    int64 // zero if not a bit field
+}
+
+func (t *StructType) String() string {
+	if t.StructName != "" {
+		return t.Kind + " " + t.StructName
+	}
+	return t.Defn()
+}
+
+func (t *StructType) Defn() string {
+	s := t.Kind
+	if t.StructName != "" {
+		s += " " + t.StructName
+	}
+	if t.Incomplete {
+		s += " /*incomplete*/"
+		return s
+	}
+	s += " {"
+	for i, f := range t.Field {
+		if i > 0 {
+			s += "; "
+		}
+		s += f.Name + " " + f.Type.String()
+		s += "@" + strconv.FormatInt(f.ByteOffset, 10)
+		if f.BitSize > 0 {
+			s += " : " + strconv.FormatInt(f.BitSize, 10)
+			s += "@" + strconv.FormatInt(f.BitOffset, 10)
+		}
+	}
+	s += "}"
+	return s
+}
+
+// An EnumType represents an enumerated type.
+// The only indication of its native integer type is its ByteSize
+// (inside CommonType).
+type EnumType struct {
+	CommonType
+	EnumName string
+	Val      []*EnumValue
+}
+
+// An EnumValue represents a single enumeration value.
+type EnumValue struct {
+	Name string
+	Val  int64
+}
+
+func (t *EnumType) String() string {
+	s := "enum"
+	if t.EnumName != "" {
+		s += " " + t.EnumName
+	}
+	s += " {"
+	for i, v := range t.Val {
+		if i > 0 {
+			s += "; "
+		}
+		s += v.Name + "=" + strconv.FormatInt(v.Val, 10)
+	}
+	s += "}"
+	return s
+}
+
+// A FuncType represents a function type.
+type FuncType struct {
+	CommonType
+	ReturnType Type
+	ParamType  []Type
+}
+
+func (t *FuncType) String() string {
+	s := "func("
+	for i, t := range t.ParamType {
+		if i > 0 {
+			s += ", "
+		}
+		s += t.String()
+	}
+	s += ")"
+	if t.ReturnType != nil {
+		s += " " + t.ReturnType.String()
+	}
+	return s
+}
+
+// A DotDotDotType represents the variadic ... function parameter.
+type DotDotDotType struct {
+	CommonType
+}
+
+func (t *DotDotDotType) String() string { return "..." }
+
+// A TypedefType represents a named type.
+type TypedefType struct {
+	CommonType
+	Type Type
+}
+
+func (t *TypedefType) String() string { return t.Name }
+
+func (t *TypedefType) Size() int64 { return t.Type.Size() }
+
+// typeReader is used to read from either the info section or the
+// types section.
+type typeReader interface {
+	Seek(Offset)
+	Next() (*Entry, error)
+	clone() typeReader
+	offset() Offset
+}
+
+// Type reads the type at off in the DWARF ``info'' section.
+func (d *Data) Type(off Offset) (Type, error) {
+	return d.readType("info", d.Reader(), off, d.typeCache)
+}
+
+// readType reads a type from r at off of name using and updating a
+// type cache.
+func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) {
+	if t, ok := typeCache[off]; ok {
+		return t, nil
+	}
+	r.Seek(off)
+	e, err := r.Next()
+	if err != nil {
+		return nil, err
+	}
+	if e == nil || e.Offset != off {
+		return nil, DecodeError{name, off, "no type at offset"}
+	}
+
+	// Parse type from Entry.
+	// Must always set typeCache[off] before calling
+	// d.Type recursively, to handle circular types correctly.
+	var typ Type
+
+	nextDepth := 0
+
+	// Get next child; set err if error happens.
+	next := func() *Entry {
+		if !e.Children {
+			return nil
+		}
+		// Only return direct children.
+		// Skip over composite entries that happen to be nested
+		// inside this one. Most DWARF generators wouldn't generate
+		// such a thing, but clang does.
+		// See golang.org/issue/6472.
+		for {
+			kid, err1 := r.Next()
+			if err1 != nil {
+				err = err1
+				return nil
+			}
+			if kid == nil {
+				err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"}
+				return nil
+			}
+			if kid.Tag == 0 {
+				if nextDepth > 0 {
+					nextDepth--
+					continue
+				}
+				return nil
+			}
+			if kid.Children {
+				nextDepth++
+			}
+			if nextDepth > 0 {
+				continue
+			}
+			return kid
+		}
+	}
+
+	// Get Type referred to by Entry's AttrType field.
+	// Set err if error happens.  Not having a type is an error.
+	typeOf := func(e *Entry) Type {
+		tval := e.Val(AttrType)
+		var t Type
+		switch toff := tval.(type) {
+		case Offset:
+			if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil {
+				return nil
+			}
+		case uint64:
+			if t, err = d.sigToType(toff); err != nil {
+				return nil
+			}
+		default:
+			// It appears that no Type means "void".
+			return new(VoidType)
+		}
+		return t
+	}
+
+	switch e.Tag {
+	case TagArrayType:
+		// Multi-dimensional array.  (DWARF v2 §5.4)
+		// Attributes:
+		//	AttrType:subtype [required]
+		//	AttrStrideSize: size in bits of each element of the array
+		//	AttrByteSize: size of entire array
+		// Children:
+		//	TagSubrangeType or TagEnumerationType giving one dimension.
+		//	dimensions are in left to right order.
+		t := new(ArrayType)
+		typ = t
+		typeCache[off] = t
+		if t.Type = typeOf(e); err != nil {
+			goto Error
+		}
+		t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
+
+		// Accumulate dimensions,
+		ndim := 0
+		for kid := next(); kid != nil; kid = next() {
+			// TODO(rsc): Can also be TagEnumerationType
+			// but haven't seen that in the wild yet.
+			switch kid.Tag {
+			case TagSubrangeType:
+				max, ok := kid.Val(AttrUpperBound).(int64)
+				if !ok {
+					max = -2 // Count == -1, as in x[].
+				}
+				if ndim == 0 {
+					t.Count = max + 1
+				} else {
+					// Multidimensional array.
+					// Create new array type underneath this one.
+					t.Type = &ArrayType{Type: t.Type, Count: max + 1}
+				}
+				ndim++
+			case TagEnumerationType:
+				err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"}
+				goto Error
+			}
+		}
+		if ndim == 0 {
+			// LLVM generates this for x[].
+			t.Count = -1
+		}
+
+	case TagBaseType:
+		// Basic type.  (DWARF v2 §5.1)
+		// Attributes:
+		//	AttrName: name of base type in programming language of the compilation unit [required]
+		//	AttrEncoding: encoding value for type (encFloat etc) [required]
+		//	AttrByteSize: size of type in bytes [required]
+		//	AttrBitOffset: for sub-byte types, size in bits
+		//	AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes
+		name, _ := e.Val(AttrName).(string)
+		enc, ok := e.Val(AttrEncoding).(int64)
+		if !ok {
+			err = DecodeError{name, e.Offset, "missing encoding attribute for " + name}
+			goto Error
+		}
+		switch enc {
+		default:
+			err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"}
+			goto Error
+
+		case encAddress:
+			typ = new(AddrType)
+		case encBoolean:
+			typ = new(BoolType)
+		case encComplexFloat:
+			typ = new(ComplexType)
+		case encFloat:
+			typ = new(FloatType)
+		case encSigned:
+			typ = new(IntType)
+		case encUnsigned:
+			typ = new(UintType)
+		case encSignedChar:
+			typ = new(CharType)
+		case encUnsignedChar:
+			typ = new(UcharType)
+		}
+		typeCache[off] = typ
+		t := typ.(interface {
+			Basic() *BasicType
+		}).Basic()
+		t.Name = name
+		t.BitSize, _ = e.Val(AttrBitSize).(int64)
+		t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
+
+	case TagClassType, TagStructType, TagUnionType:
+		// Structure, union, or class type.  (DWARF v2 §5.5)
+		// Attributes:
+		//	AttrName: name of struct, union, or class
+		//	AttrByteSize: byte size [required]
+		//	AttrDeclaration: if true, struct/union/class is incomplete
+		// Children:
+		//	TagMember to describe one member.
+		//		AttrName: name of member [required]
+		//		AttrType: type of member [required]
+		//		AttrByteSize: size in bytes
+		//		AttrBitOffset: bit offset within bytes for bit fields
+		//		AttrBitSize: bit size for bit fields
+		//		AttrDataMemberLoc: location within struct [required for struct, class]
+		// There is much more to handle C++, all ignored for now.
+		t := new(StructType)
+		typ = t
+		typeCache[off] = t
+		switch e.Tag {
+		case TagClassType:
+			t.Kind = "class"
+		case TagStructType:
+			t.Kind = "struct"
+		case TagUnionType:
+			t.Kind = "union"
+		}
+		t.StructName, _ = e.Val(AttrName).(string)
+		t.Incomplete = e.Val(AttrDeclaration) != nil
+		t.Field = make([]*StructField, 0, 8)
+		var lastFieldType Type
+		var lastFieldBitOffset int64
+		for kid := next(); kid != nil; kid = next() {
+			if kid.Tag == TagMember {
+				f := new(StructField)
+				if f.Type = typeOf(kid); err != nil {
+					goto Error
+				}
+				switch loc := kid.Val(AttrDataMemberLoc).(type) {
+				case []byte:
+					// TODO: Should have original compilation
+					// unit here, not unknownFormat.
+					b := makeBuf(d, unknownFormat{}, "location", 0, loc)
+					if b.uint8() != opPlusUconst {
+						err = DecodeError{name, kid.Offset, "unexpected opcode"}
+						goto Error
+					}
+					f.ByteOffset = int64(b.uint())
+					if b.err != nil {
+						err = b.err
+						goto Error
+					}
+				case int64:
+					f.ByteOffset = loc
+				}
+
+				haveBitOffset := false
+				f.Name, _ = kid.Val(AttrName).(string)
+				f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
+				f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64)
+				f.BitSize, _ = kid.Val(AttrBitSize).(int64)
+				t.Field = append(t.Field, f)
+
+				bito := f.BitOffset
+				if !haveBitOffset {
+					bito = f.ByteOffset * 8
+				}
+				if bito == lastFieldBitOffset && t.Kind != "union" {
+					// Last field was zero width.  Fix array length.
+					// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
+					zeroArray(lastFieldType)
+				}
+				lastFieldType = f.Type
+				lastFieldBitOffset = bito
+			}
+		}
+		if t.Kind != "union" {
+			b, ok := e.Val(AttrByteSize).(int64)
+			if ok && b*8 == lastFieldBitOffset {
+				// Final field must be zero width.  Fix array length.
+				zeroArray(lastFieldType)
+			}
+		}
+
+	case TagConstType, TagVolatileType, TagRestrictType:
+		// Type modifier (DWARF v2 §5.2)
+		// Attributes:
+		//	AttrType: subtype
+		t := new(QualType)
+		typ = t
+		typeCache[off] = t
+		if t.Type = typeOf(e); err != nil {
+			goto Error
+		}
+		switch e.Tag {
+		case TagConstType:
+			t.Qual = "const"
+		case TagRestrictType:
+			t.Qual = "restrict"
+		case TagVolatileType:
+			t.Qual = "volatile"
+		}
+
+	case TagEnumerationType:
+		// Enumeration type (DWARF v2 §5.6)
+		// Attributes:
+		//	AttrName: enum name if any
+		//	AttrByteSize: bytes required to represent largest value
+		// Children:
+		//	TagEnumerator:
+		//		AttrName: name of constant
+		//		AttrConstValue: value of constant
+		t := new(EnumType)
+		typ = t
+		typeCache[off] = t
+		t.EnumName, _ = e.Val(AttrName).(string)
+		t.Val = make([]*EnumValue, 0, 8)
+		for kid := next(); kid != nil; kid = next() {
+			if kid.Tag == TagEnumerator {
+				f := new(EnumValue)
+				f.Name, _ = kid.Val(AttrName).(string)
+				f.Val, _ = kid.Val(AttrConstValue).(int64)
+				n := len(t.Val)
+				if n >= cap(t.Val) {
+					val := make([]*EnumValue, n, n*2)
+					copy(val, t.Val)
+					t.Val = val
+				}
+				t.Val = t.Val[0 : n+1]
+				t.Val[n] = f
+			}
+		}
+
+	case TagPointerType:
+		// Type modifier (DWARF v2 §5.2)
+		// Attributes:
+		//	AttrType: subtype [not required!  void* has no AttrType]
+		//	AttrAddrClass: address class [ignored]
+		t := new(PtrType)
+		typ = t
+		typeCache[off] = t
+		if e.Val(AttrType) == nil {
+			t.Type = &VoidType{}
+			break
+		}
+		t.Type = typeOf(e)
+
+	case TagSubroutineType:
+		// Subroutine type.  (DWARF v2 §5.7)
+		// Attributes:
+		//	AttrType: type of return value if any
+		//	AttrName: possible name of type [ignored]
+		//	AttrPrototyped: whether used ANSI C prototype [ignored]
+		// Children:
+		//	TagFormalParameter: typed parameter
+		//		AttrType: type of parameter
+		//	TagUnspecifiedParameter: final ...
+		t := new(FuncType)
+		typ = t
+		typeCache[off] = t
+		if t.ReturnType = typeOf(e); err != nil {
+			goto Error
+		}
+		t.ParamType = make([]Type, 0, 8)
+		for kid := next(); kid != nil; kid = next() {
+			var tkid Type
+			switch kid.Tag {
+			default:
+				continue
+			case TagFormalParameter:
+				if tkid = typeOf(kid); err != nil {
+					goto Error
+				}
+			case TagUnspecifiedParameters:
+				tkid = &DotDotDotType{}
+			}
+			t.ParamType = append(t.ParamType, tkid)
+		}
+
+	case TagTypedef:
+		// Typedef (DWARF v2 §5.3)
+		// Attributes:
+		//	AttrName: name [required]
+		//	AttrType: type definition [required]
+		t := new(TypedefType)
+		typ = t
+		typeCache[off] = t
+		t.Name, _ = e.Val(AttrName).(string)
+		t.Type = typeOf(e)
+	}
+
+	if err != nil {
+		goto Error
+	}
+
+	{
+		b, ok := e.Val(AttrByteSize).(int64)
+		if !ok {
+			b = -1
+		}
+		typ.Common().ByteSize = b
+	}
+	return typ, nil
+
+Error:
+	// If the parse fails, take the type out of the cache
+	// so that the next call with this offset doesn't hit
+	// the cache and return success.
+	delete(typeCache, off)
+	return nil, err
+}
+
+func zeroArray(t Type) {
+	for {
+		at, ok := t.(*ArrayType)
+		if !ok {
+			break
+		}
+		at.Count = 0
+		t = at.Type
+	}
+}
diff --git a/debug/dwarf/type_test.go b/debug/dwarf/type_test.go
new file mode 100644
index 0000000..2cb85e7
--- /dev/null
+++ b/debug/dwarf/type_test.go
@@ -0,0 +1,122 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf_test
+
+import (
+	. "debug/dwarf"
+	"debug/elf"
+	"debug/macho"
+	"testing"
+)
+
+var typedefTests = map[string]string{
+	"t_ptr_volatile_int":                    "*volatile int",
+	"t_ptr_const_char":                      "*const char",
+	"t_long":                                "long int",
+	"t_ushort":                              "short unsigned int",
+	"t_func_int_of_float_double":            "func(float, double) int",
+	"t_ptr_func_int_of_float_double":        "*func(float, double) int",
+	"t_ptr_func_int_of_float_complex":       "*func(complex float) int",
+	"t_ptr_func_int_of_double_complex":      "*func(complex double) int",
+	"t_ptr_func_int_of_long_double_complex": "*func(complex long double) int",
+	"t_func_ptr_int_of_char_schar_uchar":    "func(char, signed char, unsigned char) *int",
+	"t_func_void_of_char":                   "func(char) void",
+	"t_func_void_of_void":                   "func() void",
+	"t_func_void_of_ptr_char_dots":          "func(*char, ...) void",
+	"t_my_struct":                           "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; z [0]int@8; array [40]long long int@8; zz [0]int@328}",
+	"t_my_struct1":                          "struct my_struct1 {zz [1]int@0}",
+	"t_my_union":                            "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
+	"t_my_enum":                             "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
+	"t_my_list":                             "struct list {val short int@0; next *t_my_list@8}",
+	"t_my_tree":                             "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
+}
+
+// As Apple converts gcc to a clang-based front end
+// they keep breaking the DWARF output.  This map lists the
+// conversion from real answer to Apple answer.
+var machoBug = map[string]string{
+	"func(*char, ...) void":                                 "func(*char) void",
+	"enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}": "enum my_enum {e1=1; e2=2; e3=-5; e4=-1530494976}",
+}
+
+func elfData(t *testing.T, name string) *Data {
+	f, err := elf.Open(name)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	d, err := f.DWARF()
+	if err != nil {
+		t.Fatal(err)
+	}
+	return d
+}
+
+func machoData(t *testing.T, name string) *Data {
+	f, err := macho.Open(name)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	d, err := f.DWARF()
+	if err != nil {
+		t.Fatal(err)
+	}
+	return d
+}
+
+func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf") }
+
+func TestTypedefsMachO(t *testing.T) {
+	testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
+}
+
+func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") }
+
+func testTypedefs(t *testing.T, d *Data, kind string) {
+	r := d.Reader()
+	seen := make(map[string]bool)
+	for {
+		e, err := r.Next()
+		if err != nil {
+			t.Fatal("r.Next:", err)
+		}
+		if e == nil {
+			break
+		}
+		if e.Tag == TagTypedef {
+			typ, err := d.Type(e.Offset)
+			if err != nil {
+				t.Fatal("d.Type:", err)
+			}
+			t1 := typ.(*TypedefType)
+			var typstr string
+			if ts, ok := t1.Type.(*StructType); ok {
+				typstr = ts.Defn()
+			} else {
+				typstr = t1.Type.String()
+			}
+
+			if want, ok := typedefTests[t1.Name]; ok {
+				if seen[t1.Name] {
+					t.Errorf("multiple definitions for %s", t1.Name)
+				}
+				seen[t1.Name] = true
+				if typstr != want && (kind != "macho" || typstr != machoBug[want]) {
+					t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
+				}
+			}
+		}
+		if e.Tag != TagCompileUnit {
+			r.SkipChildren()
+		}
+	}
+
+	for k := range typedefTests {
+		if !seen[k] {
+			t.Errorf("missing %s", k)
+		}
+	}
+}
diff --git a/debug/dwarf/typeunit.go b/debug/dwarf/typeunit.go
new file mode 100644
index 0000000..3fd1c99
--- /dev/null
+++ b/debug/dwarf/typeunit.go
@@ -0,0 +1,166 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf
+
+import (
+	"fmt"
+	"strconv"
+)
+
+// Parse the type units stored in a DWARF4 .debug_types section.  Each
+// type unit defines a single primary type and an 8-byte signature.
+// Other sections may then use formRefSig8 to refer to the type.
+
+// The typeUnit format is a single type with a signature.  It holds
+// the same data as a compilation unit.
+type typeUnit struct {
+	unit
+	toff  Offset // Offset to signature type within data.
+	name  string // Name of .debug_type section.
+	cache Type   // Cache the type, nil to start.
+}
+
+// Parse a .debug_types section.
+func (d *Data) parseTypes(name string, types []byte) error {
+	b := makeBuf(d, unknownFormat{}, name, 0, types)
+	for len(b.data) > 0 {
+		base := b.off
+		dwarf64 := false
+		n := b.uint32()
+		if n == 0xffffffff {
+			n64 := b.uint64()
+			if n64 != uint64(uint32(n64)) {
+				b.error("type unit length overflow")
+				return b.err
+			}
+			n = uint32(n64)
+			dwarf64 = true
+		}
+		hdroff := b.off
+		vers := b.uint16()
+		if vers != 4 {
+			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+			return b.err
+		}
+		var ao uint32
+		if !dwarf64 {
+			ao = b.uint32()
+		} else {
+			ao64 := b.uint64()
+			if ao64 != uint64(uint32(ao64)) {
+				b.error("type unit abbrev offset overflow")
+				return b.err
+			}
+			ao = uint32(ao64)
+		}
+		atable, err := d.parseAbbrev(ao)
+		if err != nil {
+			return err
+		}
+		asize := b.uint8()
+		sig := b.uint64()
+
+		var toff uint32
+		if !dwarf64 {
+			toff = b.uint32()
+		} else {
+			to64 := b.uint64()
+			if to64 != uint64(uint32(to64)) {
+				b.error("type unit type offset overflow")
+				return b.err
+			}
+			toff = uint32(to64)
+		}
+
+		boff := b.off
+		d.typeSigs[sig] = &typeUnit{
+			unit: unit{
+				base:   base,
+				off:    boff,
+				data:   b.bytes(int(Offset(n) - (b.off - hdroff))),
+				atable: atable,
+				asize:  int(asize),
+				vers:   int(vers),
+				is64:   dwarf64,
+			},
+			toff: Offset(toff),
+			name: name,
+		}
+		if b.err != nil {
+			return b.err
+		}
+	}
+	return nil
+}
+
+// Return the type for a type signature.
+func (d *Data) sigToType(sig uint64) (Type, error) {
+	tu := d.typeSigs[sig]
+	if tu == nil {
+		return nil, fmt.Errorf("no type unit with signature %v", sig)
+	}
+	if tu.cache != nil {
+		return tu.cache, nil
+	}
+
+	b := makeBuf(d, tu, tu.name, tu.off, tu.data)
+	r := &typeUnitReader{d: d, tu: tu, b: b}
+	t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
+	if err != nil {
+		return nil, err
+	}
+
+	tu.cache = t
+	return t, nil
+}
+
+// typeUnitReader is a typeReader for a tagTypeUnit.
+type typeUnitReader struct {
+	d   *Data
+	tu  *typeUnit
+	b   buf
+	err error
+}
+
+// Seek to a new position in the type unit.
+func (tur *typeUnitReader) Seek(off Offset) {
+	tur.err = nil
+	doff := off - tur.tu.off
+	if doff < 0 || doff >= Offset(len(tur.tu.data)) {
+		tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
+		return
+	}
+	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
+}
+
+// Next reads the next Entry from the type unit.
+func (tur *typeUnitReader) Next() (*Entry, error) {
+	if tur.err != nil {
+		return nil, tur.err
+	}
+	if len(tur.tu.data) == 0 {
+		return nil, nil
+	}
+	e := tur.b.entry(tur.tu.atable, tur.tu.base)
+	if tur.b.err != nil {
+		tur.err = tur.b.err
+		return nil, tur.err
+	}
+	return e, nil
+}
+
+// clone returns a new reader for the type unit.
+func (tur *typeUnitReader) clone() typeReader {
+	return &typeUnitReader{
+		d:  tur.d,
+		tu: tur.tu,
+		b:  makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data),
+	}
+}
+
+// offset returns the current offset.
+func (tur *typeUnitReader) offset() Offset {
+	return tur.b.off
+}
diff --git a/debug/dwarf/unit.go b/debug/dwarf/unit.go
new file mode 100644
index 0000000..0fbc8e0
--- /dev/null
+++ b/debug/dwarf/unit.go
@@ -0,0 +1,90 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf
+
+import "strconv"
+
+// DWARF debug info is split into a sequence of compilation units.
+// Each unit has its own abbreviation table and address size.
+
+type unit struct {
+	base   Offset // byte offset of header within the aggregate info
+	off    Offset // byte offset of data within the aggregate info
+	data   []byte
+	atable abbrevTable
+	asize  int
+	vers   int
+	is64   bool // True for 64-bit DWARF format
+}
+
+// Implement the dataFormat interface.
+
+func (u *unit) version() int {
+	return u.vers
+}
+
+func (u *unit) dwarf64() (bool, bool) {
+	return u.is64, true
+}
+
+func (u *unit) addrsize() int {
+	return u.asize
+}
+
+func (d *Data) parseUnits() ([]unit, error) {
+	// Count units.
+	nunit := 0
+	b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
+	for len(b.data) > 0 {
+		len := b.uint32()
+		if len == 0xffffffff {
+			len64 := b.uint64()
+			if len64 != uint64(uint32(len64)) {
+				b.error("unit length overflow")
+				break
+			}
+			len = uint32(len64)
+		}
+		b.skip(int(len))
+		nunit++
+	}
+	if b.err != nil {
+		return nil, b.err
+	}
+
+	// Again, this time writing them down.
+	b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
+	units := make([]unit, nunit)
+	for i := range units {
+		u := &units[i]
+		u.base = b.off
+		n := b.uint32()
+		if n == 0xffffffff {
+			u.is64 = true
+			n = uint32(b.uint64())
+		}
+		vers := b.uint16()
+		if vers != 2 && vers != 3 && vers != 4 {
+			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+			break
+		}
+		u.vers = int(vers)
+		atable, err := d.parseAbbrev(b.uint32())
+		if err != nil {
+			if b.err == nil {
+				b.err = err
+			}
+			break
+		}
+		u.atable = atable
+		u.asize = int(b.uint8())
+		u.off = b.off
+		u.data = b.bytes(int(n - (2 + 4 + 1)))
+	}
+	if b.err != nil {
+		return nil, b.err
+	}
+	return units, nil
+}