// 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 (
	
	
	
	
)

// 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
	class Class
	val   int64 // for formImplicitConst
}

// 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 ( *Data) ( uint64,  int) (abbrevTable, error) {
	if ,  := .abbrevCache[];  {
		return , nil
	}

	 := .abbrev
	if  > uint64(len()) {
		 = nil
	} else {
		 = [:]
	}
	 := makeBuf(, unknownFormat{}, "abbrev", 0, )

	// Error handling is simplified by the buf getters
	// returning an endless stream of 0s after an error.
	 := make(abbrevTable)
	for {
		// Table ends with id == 0.
		 := uint32(.uint())
		if  == 0 {
			break
		}

		// Walk over attributes, counting.
		 := 0
		 :=  // Read from copy of b.
		.uint()
		.uint8()
		for {
			 := .uint()
			 := .uint()
			if  == 0 &&  == 0 {
				break
			}
			if format() == formImplicitConst {
				.int()
			}
			++
		}
		if .err != nil {
			return nil, .err
		}

		// Walk over attributes again, this time writing them down.
		var  abbrev
		.tag = Tag(.uint())
		.children = .uint8() != 0
		.field = make([]afield, )
		for  := range .field {
			.field[].attr = Attr(.uint())
			.field[].fmt = format(.uint())
			.field[].class = formToClass(.field[].fmt, .field[].attr, , &)
			if .field[].fmt == formImplicitConst {
				.field[].val = .int()
			}
		}
		.uint()
		.uint()

		[] = 
	}
	if .err != nil {
		return nil, .err
	}
	.abbrevCache[] = 
	return , nil
}

// attrIsExprloc indicates attributes that allow exprloc values that
// are encoded as block values in DWARF 2 and 3. See DWARF 4, Figure
// 20.
var attrIsExprloc = map[Attr]bool{
	AttrLocation:      true,
	AttrByteSize:      true,
	AttrBitOffset:     true,
	AttrBitSize:       true,
	AttrStringLength:  true,
	AttrLowerBound:    true,
	AttrReturnAddr:    true,
	AttrStrideSize:    true,
	AttrUpperBound:    true,
	AttrCount:         true,
	AttrDataMemberLoc: true,
	AttrFrameBase:     true,
	AttrSegment:       true,
	AttrStaticLink:    true,
	AttrUseLocation:   true,
	AttrVtableElemLoc: true,
	AttrAllocated:     true,
	AttrAssociated:    true,
	AttrDataLocation:  true,
	AttrStride:        true,
}

// attrPtrClass indicates the *ptr class of attributes that have
// encoding formSecOffset in DWARF 4 or formData* in DWARF 2 and 3.
var attrPtrClass = map[Attr]Class{
	AttrLocation:      ClassLocListPtr,
	AttrStmtList:      ClassLinePtr,
	AttrStringLength:  ClassLocListPtr,
	AttrReturnAddr:    ClassLocListPtr,
	AttrStartScope:    ClassRangeListPtr,
	AttrDataMemberLoc: ClassLocListPtr,
	AttrFrameBase:     ClassLocListPtr,
	AttrMacroInfo:     ClassMacPtr,
	AttrSegment:       ClassLocListPtr,
	AttrStaticLink:    ClassLocListPtr,
	AttrUseLocation:   ClassLocListPtr,
	AttrVtableElemLoc: ClassLocListPtr,
	AttrRanges:        ClassRangeListPtr,
	// The following are new in DWARF 5.
	AttrStrOffsetsBase: ClassStrOffsetsPtr,
	AttrAddrBase:       ClassAddrPtr,
	AttrRnglistsBase:   ClassRngListsPtr,
	AttrLoclistsBase:   ClassLocListPtr,
}

// formToClass returns the DWARF 4 Class for the given form. If the
// DWARF version is less then 4, it will disambiguate some forms
// depending on the attribute.
func formToClass( format,  Attr,  int,  *buf) Class {
	switch  {
	default:
		.error("cannot determine class of unknown attribute form")
		return 0

	case formIndirect:
		return ClassUnknown

	case formAddr, formAddrx, formAddrx1, formAddrx2, formAddrx3, formAddrx4:
		return ClassAddress

	case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock:
		// In DWARF 2 and 3, ClassExprLoc was encoded as a
		// block. DWARF 4 distinguishes ClassBlock and
		// ClassExprLoc, but there are no attributes that can
		// be both, so we also promote ClassBlock values in
		// DWARF 4 that should be ClassExprLoc in case
		// producers get this wrong.
		if attrIsExprloc[] {
			return ClassExprLoc
		}
		return ClassBlock

	case formData1, formData2, formData4, formData8, formSdata, formUdata, formData16, formImplicitConst:
		// In DWARF 2 and 3, ClassPtr was encoded as a
		// constant. Unlike ClassExprLoc/ClassBlock, some
		// DWARF 4 attributes need to distinguish Class*Ptr
		// from ClassConstant, so we only do this promotion
		// for versions 2 and 3.
		if ,  := attrPtrClass[];  < 4 &&  {
			return 
		}
		return ClassConstant

	case formFlag, formFlagPresent:
		return ClassFlag

	case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata, formRefSup4, formRefSup8:
		return ClassReference

	case formRefSig8:
		return ClassReferenceSig

	case formString, formStrp, formStrx, formStrpSup, formLineStrp, formStrx1, formStrx2, formStrx3, formStrx4:
		return ClassString

	case formSecOffset:
		// DWARF 4 defines four *ptr classes, but doesn't
		// distinguish them in the encoding. Disambiguate
		// these classes using the attribute.
		if ,  := attrPtrClass[];  {
			return 
		}
		return ClassUnknown

	case formExprloc:
		return ClassExprLoc

	case formGnuRefAlt:
		return ClassReferenceAlt

	case formGnuStrpAlt:
		return ClassStringAlt

	case formLoclistx:
		return ClassLocList

	case formRnglistx:
		return ClassRngList
	}
}

// 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].
//
// A value can be one of several "attribute classes" defined by DWARF.
// The Go types corresponding to each class are:
//
//	DWARF class       Go type        Class
//	-----------       -------        -----
//	address           uint64         ClassAddress
//	block             []byte         ClassBlock
//	constant          int64          ClassConstant
//	flag              bool           ClassFlag
//	reference
//	  to info         dwarf.Offset   ClassReference
//	  to type unit    uint64         ClassReferenceSig
//	string            string         ClassString
//	exprloc           []byte         ClassExprLoc
//	lineptr           int64          ClassLinePtr
//	loclistptr        int64          ClassLocListPtr
//	macptr            int64          ClassMacPtr
//	rangelistptr      int64          ClassRangeListPtr
//
// For unrecognized or vendor-defined attributes, [Class] may be
// [ClassUnknown].
type Field struct {
	Attr  Attr
	Val   any
	Class Class
}

// A Class is the DWARF 4 class of an attribute value.
//
// In general, a given attribute's value may take on one of several
// possible classes defined by DWARF, each of which leads to a
// slightly different interpretation of the attribute.
//
// DWARF version 4 distinguishes attribute value classes more finely
// than previous versions of DWARF. The reader will disambiguate
// coarser classes from earlier versions of DWARF into the appropriate
// DWARF 4 class. For example, DWARF 2 uses "constant" for constants
// as well as all types of section offsets, but the reader will
// canonicalize attributes in DWARF 2 files that refer to section
// offsets to one of the Class*Ptr classes, even though these classes
// were only defined in DWARF 3.
type Class int

const (
	// ClassUnknown represents values of unknown DWARF class.
	ClassUnknown Class = iota

	// ClassAddress represents values of type uint64 that are
	// addresses on the target machine.
	ClassAddress

	// ClassBlock represents values of type []byte whose
	// interpretation depends on the attribute.
	ClassBlock

	// ClassConstant represents values of type int64 that are
	// constants. The interpretation of this constant depends on
	// the attribute.
	ClassConstant

	// ClassExprLoc represents values of type []byte that contain
	// an encoded DWARF expression or location description.
	ClassExprLoc

	// ClassFlag represents values of type bool.
	ClassFlag

	// ClassLinePtr represents values that are an int64 offset
	// into the "line" section.
	ClassLinePtr

	// ClassLocListPtr represents values that are an int64 offset
	// into the "loclist" section.
	ClassLocListPtr

	// ClassMacPtr represents values that are an int64 offset into
	// the "mac" section.
	ClassMacPtr

	// ClassRangeListPtr represents values that are an int64 offset into
	// the "rangelist" section.
	ClassRangeListPtr

	// ClassReference represents values that are an Offset offset
	// of an Entry in the info section (for use with Reader.Seek).
	// The DWARF specification combines ClassReference and
	// ClassReferenceSig into class "reference".
	ClassReference

	// ClassReferenceSig represents values that are a uint64 type
	// signature referencing a type Entry.
	ClassReferenceSig

	// ClassString represents values that are strings. If the
	// compilation unit specifies the AttrUseUTF8 flag (strongly
	// recommended), the string value will be encoded in UTF-8.
	// Otherwise, the encoding is unspecified.
	ClassString

	// ClassReferenceAlt represents values of type int64 that are
	// an offset into the DWARF "info" section of an alternate
	// object file.
	ClassReferenceAlt

	// ClassStringAlt represents values of type int64 that are an
	// offset into the DWARF string section of an alternate object
	// file.
	ClassStringAlt

	// ClassAddrPtr represents values that are an int64 offset
	// into the "addr" section.
	ClassAddrPtr

	// ClassLocList represents values that are an int64 offset
	// into the "loclists" section.
	ClassLocList

	// ClassRngList represents values that are a uint64 offset
	// from the base of the "rnglists" section.
	ClassRngList

	// ClassRngListsPtr represents values that are an int64 offset
	// into the "rnglists" section. These are used as the base for
	// ClassRngList values.
	ClassRngListsPtr

	// ClassStrOffsetsPtr represents values that are an int64
	// offset into the "str_offsets" section.
	ClassStrOffsetsPtr
)

//go:generate stringer -type=Class

func ( Class) () string {
	return "dwarf." + .String()
}

// 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 ( *Entry) ( Attr) any {
	if  := .AttrField();  != nil {
		return .Val
	}
	return nil
}

// AttrField returns the [Field] associated with attribute [Attr] in
// [Entry], or nil if there is no such attribute.
func ( *Entry) ( Attr) *Field {
	for ,  := range .Field {
		if .Attr ==  {
			return &.Field[]
		}
	}
	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 ( *buf) ( *Entry,  abbrevTable,  Offset,  int) *Entry {
	 := .off
	 := uint32(.uint())
	if  == 0 {
		return &Entry{}
	}
	,  := []
	if ! {
		.error("unknown abbreviation table index")
		return nil
	}
	 := &Entry{
		Offset:   ,
		Tag:      .tag,
		Children: .children,
		Field:    make([]Field, len(.field)),
	}

	// If we are currently parsing the compilation unit,
	// we can't evaluate Addrx or Strx until we've seen the
	// relevant base entry.
	type  struct {
		 int
		 uint64
		 format
	}
	var  []

	 := func(,  uint64) string {
		 += 
		if uint64(int()) !=  {
			.error("DW_FORM_strx offset out of range")
		}

		 := makeBuf(.dwarf, .format, "str_offsets", 0, .dwarf.strOffsets)
		.skip(int())
		,  := .format.dwarf64()
		if  {
			 = .uint64()
		} else {
			 = uint64(.uint32())
		}
		if .err != nil {
			.err = .err
			return ""
		}
		if uint64(int()) !=  {
			.error("DW_FORM_strx indirect offset out of range")
		}
		 = makeBuf(.dwarf, .format, "str", 0, .dwarf.str)
		.skip(int())
		 := .string()
		if .err != nil {
			.err = .err
		}
		return 
	}

	 := func(,  uint64) uint64 {
		,  := .format.dwarf64()
		if  {
			 *= 8
		} else {
			 *= 4
		}
		 += 
		if uint64(int()) !=  {
			.error("DW_FORM_rnglistx offset out of range")
		}

		 := makeBuf(.dwarf, .format, "rnglists", 0, .dwarf.rngLists)
		.skip(int())
		if  {
			 = .uint64()
		} else {
			 = uint64(.uint32())
		}
		if .err != nil {
			.err = .err
			return 0
		}
		if uint64(int()) !=  {
			.error("DW_FORM_rnglistx indirect offset out of range")
		}
		return  + 
	}

	for  := range .Field {
		.Field[].Attr = .field[].attr
		.Field[].Class = .field[].class
		 := .field[].fmt
		if  == formIndirect {
			 = format(.uint())
			.Field[].Class = formToClass(, .field[].attr, , )
		}
		var  any
		switch  {
		default:
			.error("unknown entry attr format 0x" + strconv.FormatInt(int64(), 16))

		// address
		case formAddr:
			 = .addr()
		case formAddrx, formAddrx1, formAddrx2, formAddrx3, formAddrx4:
			var  uint64
			switch  {
			case formAddrx:
				 = .uint()
			case formAddrx1:
				 = uint64(.uint8())
			case formAddrx2:
				 = uint64(.uint16())
			case formAddrx3:
				 = uint64(.uint24())
			case formAddrx4:
				 = uint64(.uint32())
			}
			if .dwarf.addr == nil {
				.error("DW_FORM_addrx with no .debug_addr section")
			}
			if .err != nil {
				return nil
			}

			// We have to adjust by the offset of the
			// compilation unit. This won't work if the
			// program uses Reader.Seek to skip over the
			// unit. Not much we can do about that.
			var  int64
			if  != nil {
				, _ = .Val(AttrAddrBase).(int64)
			} else if .tag == TagCompileUnit {
				 = append(, {, , formAddrx})
				break
			}

			var  error
			,  = .dwarf.debugAddr(.format, uint64(), )
			if  != nil {
				if .err == nil {
					.err = 
				}
				return nil
			}

		// block
		case formDwarfBlock1:
			 = .bytes(int(.uint8()))
		case formDwarfBlock2:
			 = .bytes(int(.uint16()))
		case formDwarfBlock4:
			 = .bytes(int(.uint32()))
		case formDwarfBlock:
			 = .bytes(int(.uint()))

		// constant
		case formData1:
			 = int64(.uint8())
		case formData2:
			 = int64(.uint16())
		case formData4:
			 = int64(.uint32())
		case formData8:
			 = int64(.uint64())
		case formData16:
			 = .bytes(16)
		case formSdata:
			 = int64(.int())
		case formUdata:
			 = int64(.uint())
		case formImplicitConst:
			 = .field[].val

		// flag
		case formFlag:
			 = .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.
			 = true

		// reference to other entry
		case formRefAddr:
			 := .format.version()
			if  == 0 {
				.error("unknown version for DW_FORM_ref_addr")
			} else if  == 2 {
				 = Offset(.addr())
			} else {
				,  := .format.dwarf64()
				if ! {
					.error("unknown size for DW_FORM_ref_addr")
				} else if  {
					 = Offset(.uint64())
				} else {
					 = Offset(.uint32())
				}
			}
		case formRef1:
			 = Offset(.uint8()) + 
		case formRef2:
			 = Offset(.uint16()) + 
		case formRef4:
			 = Offset(.uint32()) + 
		case formRef8:
			 = Offset(.uint64()) + 
		case formRefUdata:
			 = Offset(.uint()) + 

		// string
		case formString:
			 = .string()
		case formStrp, formLineStrp:
			var  uint64 // offset into .debug_str
			,  := .format.dwarf64()
			if ! {
				.error("unknown size for DW_FORM_strp/line_strp")
			} else if  {
				 = .uint64()
			} else {
				 = uint64(.uint32())
			}
			if uint64(int()) !=  {
				.error("DW_FORM_strp/line_strp offset out of range")
			}
			if .err != nil {
				return nil
			}
			var  buf
			if  == formStrp {
				 = makeBuf(.dwarf, .format, "str", 0, .dwarf.str)
			} else {
				if len(.dwarf.lineStr) == 0 {
					.error("DW_FORM_line_strp with no .debug_line_str section")
					return nil
				}
				 = makeBuf(.dwarf, .format, "line_str", 0, .dwarf.lineStr)
			}
			.skip(int())
			 = .string()
			if .err != nil {
				.err = .err
				return nil
			}
		case formStrx, formStrx1, formStrx2, formStrx3, formStrx4:
			var  uint64
			switch  {
			case formStrx:
				 = .uint()
			case formStrx1:
				 = uint64(.uint8())
			case formStrx2:
				 = uint64(.uint16())
			case formStrx3:
				 = uint64(.uint24())
			case formStrx4:
				 = uint64(.uint32())
			}
			if len(.dwarf.strOffsets) == 0 {
				.error("DW_FORM_strx with no .debug_str_offsets section")
			}
			,  := .format.dwarf64()
			if ! {
				.error("unknown offset size for DW_FORM_strx")
			}
			if .err != nil {
				return nil
			}
			if  {
				 *= 8
			} else {
				 *= 4
			}

			// We have to adjust by the offset of the
			// compilation unit. This won't work if the
			// program uses Reader.Seek to skip over the
			// unit. Not much we can do about that.
			var  int64
			if  != nil {
				, _ = .Val(AttrStrOffsetsBase).(int64)
			} else if .tag == TagCompileUnit {
				 = append(, {, , formStrx})
				break
			}

			 = (uint64(), )

		case formStrpSup:
			,  := .format.dwarf64()
			if ! {
				.error("unknown size for DW_FORM_strp_sup")
			} else if  {
				 = .uint64()
			} else {
				 = .uint32()
			}

		// 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:
			,  := .format.dwarf64()
			if ! {
				.error("unknown size for form 0x" + strconv.FormatInt(int64(), 16))
			} else if  {
				 = int64(.uint64())
			} else {
				 = int64(.uint32())
			}

		// exprloc
		// New in DWARF 4.
		case formExprloc:
			 = .bytes(int(.uint()))

		// reference
		// New in DWARF 4.
		case formRefSig8:
			// 64-bit type signature.
			 = .uint64()
		case formRefSup4:
			 = .uint32()
		case formRefSup8:
			 = .uint64()

		// loclist
		case formLoclistx:
			 = .uint()

		// rnglist
		case formRnglistx:
			 := .uint()

			// We have to adjust by the rnglists_base of
			// the compilation unit. This won't work if
			// the program uses Reader.Seek to skip over
			// the unit. Not much we can do about that.
			var  int64
			if  != nil {
				, _ = .Val(AttrRnglistsBase).(int64)
			} else if .tag == TagCompileUnit {
				 = append(, {, , formRnglistx})
				break
			}

			 = (uint64(), )
		}

		.Field[].Val = 
	}
	if .err != nil {
		return nil
	}

	for ,  := range  {
		switch . {
		case formAddrx:
			,  := .Val(AttrAddrBase).(int64)
			,  := .dwarf.debugAddr(.format, uint64(), .)
			if  != nil {
				.err = 
				return nil
			}
			.Field[.].Val = 
		case formStrx:
			,  := .Val(AttrStrOffsetsBase).(int64)
			.Field[.].Val = (uint64(), .)
			if .err != nil {
				return nil
			}
		case formRnglistx:
			,  := .Val(AttrRnglistsBase).(int64)
			.Field[.].Val = (uint64(), .)
			if .err != nil {
				return nil
			}
		}
	}

	return 
}

// A Reader allows reading [Entry] structures from a DWARF “info” section.
// The [Entry] structures are arranged in a tree. The [Reader.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
	lastUnit     bool   // set if last entry returned by Next is TagCompileUnit/TagPartialUnit
	lastChildren bool   // .Children of last entry returned by Next
	lastSibling  Offset // .Val(AttrSibling) of last entry returned by Next
	cu           *Entry // current compilation unit
}

// Reader returns a new Reader for [Data].
// The reader is positioned at byte offset 0 in the DWARF “info” section.
func ( *Data) () *Reader {
	 := &Reader{d: }
	.Seek(0)
	return 
}

// AddressSize returns the size in bytes of addresses in the current compilation
// unit.
func ( *Reader) () int {
	return .d.unit[.unit].asize
}

// ByteOrder returns the byte order in the current compilation unit.
func ( *Reader) () binary.ByteOrder {
	return .b.order
}

// Seek positions the [Reader] at offset off in the encoded entry stream.
// Offset 0 can be used to denote the first entry.
func ( *Reader) ( Offset) {
	 := .d
	.err = nil
	.lastChildren = false
	if  == 0 {
		if len(.unit) == 0 {
			return
		}
		 := &.unit[0]
		.unit = 0
		.b = makeBuf(.d, , "info", .off, .data)
		.cu = nil
		return
	}

	 := .offsetToUnit()
	if  == -1 {
		.err = errors.New("offset out of range")
		return
	}
	if  != .unit {
		.cu = nil
	}
	 := &.unit[]
	.unit = 
	.b = makeBuf(.d, , "info", , .data[-.off:])
}

// maybeNextUnit advances to the next unit if this one is finished.
func ( *Reader) () {
	for len(.b.data) == 0 && .unit+1 < len(.d.unit) {
		.nextUnit()
	}
}

// nextUnit advances to the next unit.
func ( *Reader) () {
	.unit++
	 := &.d.unit[.unit]
	.b = makeBuf(.d, , "info", .off, .data)
	.cu = nil
}

// 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 ( *Reader) () (*Entry, error) {
	if .err != nil {
		return nil, .err
	}
	.maybeNextUnit()
	if len(.b.data) == 0 {
		return nil, nil
	}
	 := &.d.unit[.unit]
	 := .b.entry(.cu, .atable, .base, .vers)
	if .b.err != nil {
		.err = .b.err
		return nil, .err
	}
	.lastUnit = false
	if  != nil {
		.lastChildren = .Children
		if .lastChildren {
			.lastSibling, _ = .Val(AttrSibling).(Offset)
		}
		if .Tag == TagCompileUnit || .Tag == TagPartialUnit {
			.lastUnit = true
			.cu = 
		}
	} else {
		.lastChildren = false
	}
	return , nil
}

// SkipChildren skips over the child entries associated with
// the last [Entry] returned by [Reader.Next]. If that [Entry] did not have
// children or [Reader.Next] has not been called, SkipChildren is a no-op.
func ( *Reader) () {
	if .err != nil || !.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 .lastSibling >= .b.off {
		.Seek(.lastSibling)
		return
	}

	if .lastUnit && .unit+1 < len(.d.unit) {
		.nextUnit()
		return
	}

	for {
		,  := .Next()
		if  != nil ||  == nil || .Tag == 0 {
			break
		}
		if .Children {
			.()
		}
	}
}

// clone returns a copy of the reader. This is used by the typeReader
// interface.
func ( *Reader) () typeReader {
	return .d.Reader()
}

// offset returns the current buffer offset. This is used by the
// typeReader interface.
func ( *Reader) () Offset {
	return .b.off
}

// SeekPC returns the [Entry] for the compilation unit that includes pc,
// and positions the reader to read the children of that unit.  If pc
// is not covered by any unit, SeekPC returns [ErrUnknownPC] and the
// position of the reader is undefined.
//
// Because compilation units can describe multiple regions of the
// executable, in the worst case SeekPC must search through all the
// ranges in all the compilation units. Each call to SeekPC starts the
// search at the compilation unit of the last call, so in general
// looking up a series of PCs will be faster if they are sorted. If
// the caller wishes to do repeated fast PC lookups, it should build
// an appropriate index using the Ranges method.
func ( *Reader) ( uint64) (*Entry, error) {
	 := .unit
	for  := 0;  < len(.d.unit); ++ {
		if  >= len(.d.unit) {
			 = 0
		}
		.err = nil
		.lastChildren = false
		.unit = 
		.cu = nil
		 := &.d.unit[]
		.b = makeBuf(.d, , "info", .off, .data)
		,  := .Next()
		if  != nil {
			return nil, 
		}
		if  == nil || .Tag == 0 {
			return nil, ErrUnknownPC
		}
		,  := .d.Ranges()
		if  != nil {
			return nil, 
		}
		for ,  := range  {
			if [0] <=  &&  < [1] {
				return , nil
			}
		}
		++
	}
	return nil, ErrUnknownPC
}

// Ranges returns the PC ranges covered by e, a slice of [low,high) pairs.
// Only some entry types, such as [TagCompileUnit] or [TagSubprogram], have PC
// ranges; for others, this will return nil with no error.
func ( *Data) ( *Entry) ([][2]uint64, error) {
	var  [][2]uint64

	,  := .Val(AttrLowpc).(uint64)

	var  uint64
	var  bool
	 := .AttrField(AttrHighpc)
	if  != nil {
		switch .Class {
		case ClassAddress:
			,  = .Val.(uint64)
		case ClassConstant:
			,  := .Val.(int64)
			if  {
				 =  + uint64()
				 = true
			}
		}
	}

	if  &&  {
		 = append(, [2]uint64{, })
	}

	var  *unit
	if  := .offsetToUnit(.Offset);  >= 0 &&  < len(.unit) {
		 = &.unit[]
	}

	if  != nil && .vers >= 5 && .rngLists != nil {
		// DWARF version 5 and later
		 := .AttrField(AttrRanges)
		if  == nil {
			return , nil
		}
		switch .Class {
		case ClassRangeListPtr:
			,  := .Val.(int64)
			if ! {
				return , nil
			}
			, ,  := .baseAddressForEntry()
			if  != nil {
				return nil, 
			}
			return .dwarf5Ranges(, , , , )

		case ClassRngList:
			,  := .Val.(uint64)
			if ! {
				return , nil
			}
			, ,  := .baseAddressForEntry()
			if  != nil {
				return nil, 
			}
			return .dwarf5Ranges(, , , int64(), )

		default:
			return , nil
		}
	}

	// DWARF version 2 through 4
	,  := .Val(AttrRanges).(int64)
	if  && .ranges != nil {
		, ,  := .baseAddressForEntry()
		if  != nil {
			return nil, 
		}
		return .dwarf2Ranges(, , , )
	}

	return , nil
}

// baseAddressForEntry returns the initial base address to be used when
// looking up the range list of entry e.
// DWARF specifies that this should be the lowpc attribute of the enclosing
// compilation unit, however comments in gdb/dwarf2read.c say that some
// versions of GCC use the entrypc attribute, so we check that too.
func ( *Data) ( *Entry) (*Entry, uint64, error) {
	var  *Entry
	if .Tag == TagCompileUnit {
		 = 
	} else {
		 := .offsetToUnit(.Offset)
		if  == -1 {
			return nil, 0, errors.New("no unit for entry")
		}
		 := &.unit[]
		 := makeBuf(, , "info", .off, .data)
		 = .entry(nil, .atable, .base, .vers)
		if .err != nil {
			return nil, 0, .err
		}
	}

	if ,  := .Val(AttrEntrypc).(uint64);  {
		return , , nil
	} else if ,  := .Val(AttrLowpc).(uint64);  {
		return , , nil
	}

	return , 0, nil
}

func ( *Data) ( *unit,  uint64,  int64,  [][2]uint64) ([][2]uint64, error) {
	if  < 0 ||  > int64(len(.ranges)) {
		return nil, fmt.Errorf("invalid range offset %d (max %d)", , len(.ranges))
	}
	 := makeBuf(, , "ranges", Offset(), .ranges[:])
	for len(.data) > 0 {
		 := .addr()
		 := .addr()

		if  == 0 &&  == 0 {
			break
		}

		if  == ^uint64(0)>>uint((8-.addrsize())*8) {
			 = 
		} else {
			 = append(, [2]uint64{ + ,  + })
		}
	}

	return , nil
}

// dwarf5Ranges interprets a debug_rnglists sequence, see DWARFv5 section
// 2.17.3 (page 53).
func ( *Data) ( *unit,  *Entry,  uint64,  int64,  [][2]uint64) ([][2]uint64, error) {
	if  < 0 ||  > int64(len(.rngLists)) {
		return nil, fmt.Errorf("invalid rnglist offset %d (max %d)", , len(.ranges))
	}
	var  int64
	if  != nil {
		, _ = .Val(AttrAddrBase).(int64)
	}

	 := makeBuf(, , "rnglists", 0, .rngLists)
	.skip(int())
	for {
		 := .uint8()
		switch  {
		case rleEndOfList:
			if .err != nil {
				return nil, .err
			}
			return , nil

		case rleBaseAddressx:
			 := .uint()
			var  error
			,  = .debugAddr(, uint64(), )
			if  != nil {
				return nil, 
			}

		case rleStartxEndx:
			 := .uint()
			 := .uint()

			,  := .debugAddr(, uint64(), )
			if  != nil {
				return nil, 
			}
			,  := .debugAddr(, uint64(), )
			if  != nil {
				return nil, 
			}
			 = append(, [2]uint64{, })

		case rleStartxLength:
			 := .uint()
			 := .uint()
			,  := .debugAddr(, uint64(), )
			if  != nil {
				return nil, 
			}
			 = append(, [2]uint64{,  + })

		case rleOffsetPair:
			 := .uint()
			 := .uint()
			 = append(, [2]uint64{ + ,  + })

		case rleBaseAddress:
			 = .addr()

		case rleStartEnd:
			 := .addr()
			 := .addr()
			 = append(, [2]uint64{, })

		case rleStartLength:
			 := .addr()
			 := .uint()
			 = append(, [2]uint64{,  + })
		}
	}
}

// debugAddr returns the address at idx in debug_addr
func ( *Data) ( dataFormat, ,  uint64) (uint64, error) {
	 := *uint64(.addrsize()) + 

	if uint64(int()) !=  {
		return 0, errors.New("offset out of range")
	}

	 := makeBuf(, , "addr", 0, .addr)
	.skip(int())
	 := .addr()
	if .err != nil {
		return 0, .err
	}
	return , nil
}