Home | History | Annotate | Download | only in dwarf
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // DWARF debug information entry parser.
      6 // An entry is a sequence of data items of a given format.
      7 // The first word in the entry is an index into what DWARF
      8 // calls the ``abbreviation table.''  An abbreviation is really
      9 // just a type descriptor: it's an array of attribute tag/value format pairs.
     10 
     11 package dwarf
     12 
     13 import (
     14 	"errors"
     15 	"strconv"
     16 )
     17 
     18 // a single entry's description: a sequence of attributes
     19 type abbrev struct {
     20 	tag      Tag
     21 	children bool
     22 	field    []afield
     23 }
     24 
     25 type afield struct {
     26 	attr  Attr
     27 	fmt   format
     28 	class Class
     29 }
     30 
     31 // a map from entry format ids to their descriptions
     32 type abbrevTable map[uint32]abbrev
     33 
     34 // ParseAbbrev returns the abbreviation table that starts at byte off
     35 // in the .debug_abbrev section.
     36 func (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) {
     37 	if m, ok := d.abbrevCache[off]; ok {
     38 		return m, nil
     39 	}
     40 
     41 	data := d.abbrev
     42 	if off > uint64(len(data)) {
     43 		data = nil
     44 	} else {
     45 		data = data[off:]
     46 	}
     47 	b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
     48 
     49 	// Error handling is simplified by the buf getters
     50 	// returning an endless stream of 0s after an error.
     51 	m := make(abbrevTable)
     52 	for {
     53 		// Table ends with id == 0.
     54 		id := uint32(b.uint())
     55 		if id == 0 {
     56 			break
     57 		}
     58 
     59 		// Walk over attributes, counting.
     60 		n := 0
     61 		b1 := b // Read from copy of b.
     62 		b1.uint()
     63 		b1.uint8()
     64 		for {
     65 			tag := b1.uint()
     66 			fmt := b1.uint()
     67 			if tag == 0 && fmt == 0 {
     68 				break
     69 			}
     70 			n++
     71 		}
     72 		if b1.err != nil {
     73 			return nil, b1.err
     74 		}
     75 
     76 		// Walk over attributes again, this time writing them down.
     77 		var a abbrev
     78 		a.tag = Tag(b.uint())
     79 		a.children = b.uint8() != 0
     80 		a.field = make([]afield, n)
     81 		for i := range a.field {
     82 			a.field[i].attr = Attr(b.uint())
     83 			a.field[i].fmt = format(b.uint())
     84 			a.field[i].class = formToClass(a.field[i].fmt, a.field[i].attr, vers, &b)
     85 		}
     86 		b.uint()
     87 		b.uint()
     88 
     89 		m[id] = a
     90 	}
     91 	if b.err != nil {
     92 		return nil, b.err
     93 	}
     94 	d.abbrevCache[off] = m
     95 	return m, nil
     96 }
     97 
     98 // attrIsExprloc indicates attributes that allow exprloc values that
     99 // are encoded as block values in DWARF 2 and 3. See DWARF 4, Figure
    100 // 20.
    101 var attrIsExprloc = map[Attr]bool{
    102 	AttrLocation:      true,
    103 	AttrByteSize:      true,
    104 	AttrBitOffset:     true,
    105 	AttrBitSize:       true,
    106 	AttrStringLength:  true,
    107 	AttrLowerBound:    true,
    108 	AttrReturnAddr:    true,
    109 	AttrStrideSize:    true,
    110 	AttrUpperBound:    true,
    111 	AttrCount:         true,
    112 	AttrDataMemberLoc: true,
    113 	AttrFrameBase:     true,
    114 	AttrSegment:       true,
    115 	AttrStaticLink:    true,
    116 	AttrUseLocation:   true,
    117 	AttrVtableElemLoc: true,
    118 	AttrAllocated:     true,
    119 	AttrAssociated:    true,
    120 	AttrDataLocation:  true,
    121 	AttrStride:        true,
    122 }
    123 
    124 // attrPtrClass indicates the *ptr class of attributes that have
    125 // encoding formSecOffset in DWARF 4 or formData* in DWARF 2 and 3.
    126 var attrPtrClass = map[Attr]Class{
    127 	AttrLocation:      ClassLocListPtr,
    128 	AttrStmtList:      ClassLinePtr,
    129 	AttrStringLength:  ClassLocListPtr,
    130 	AttrReturnAddr:    ClassLocListPtr,
    131 	AttrStartScope:    ClassRangeListPtr,
    132 	AttrDataMemberLoc: ClassLocListPtr,
    133 	AttrFrameBase:     ClassLocListPtr,
    134 	AttrMacroInfo:     ClassMacPtr,
    135 	AttrSegment:       ClassLocListPtr,
    136 	AttrStaticLink:    ClassLocListPtr,
    137 	AttrUseLocation:   ClassLocListPtr,
    138 	AttrVtableElemLoc: ClassLocListPtr,
    139 	AttrRanges:        ClassRangeListPtr,
    140 }
    141 
    142 // formToClass returns the DWARF 4 Class for the given form. If the
    143 // DWARF version is less then 4, it will disambiguate some forms
    144 // depending on the attribute.
    145 func formToClass(form format, attr Attr, vers int, b *buf) Class {
    146 	switch form {
    147 	default:
    148 		b.error("cannot determine class of unknown attribute form")
    149 		return 0
    150 
    151 	case formAddr:
    152 		return ClassAddress
    153 
    154 	case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock:
    155 		// In DWARF 2 and 3, ClassExprLoc was encoded as a
    156 		// block. DWARF 4 distinguishes ClassBlock and
    157 		// ClassExprLoc, but there are no attributes that can
    158 		// be both, so we also promote ClassBlock values in
    159 		// DWARF 4 that should be ClassExprLoc in case
    160 		// producers get this wrong.
    161 		if attrIsExprloc[attr] {
    162 			return ClassExprLoc
    163 		}
    164 		return ClassBlock
    165 
    166 	case formData1, formData2, formData4, formData8, formSdata, formUdata:
    167 		// In DWARF 2 and 3, ClassPtr was encoded as a
    168 		// constant. Unlike ClassExprLoc/ClassBlock, some
    169 		// DWARF 4 attributes need to distinguish Class*Ptr
    170 		// from ClassConstant, so we only do this promotion
    171 		// for versions 2 and 3.
    172 		if class, ok := attrPtrClass[attr]; vers < 4 && ok {
    173 			return class
    174 		}
    175 		return ClassConstant
    176 
    177 	case formFlag, formFlagPresent:
    178 		return ClassFlag
    179 
    180 	case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata:
    181 		return ClassReference
    182 
    183 	case formRefSig8:
    184 		return ClassReferenceSig
    185 
    186 	case formString, formStrp:
    187 		return ClassString
    188 
    189 	case formSecOffset:
    190 		// DWARF 4 defines four *ptr classes, but doesn't
    191 		// distinguish them in the encoding. Disambiguate
    192 		// these classes using the attribute.
    193 		if class, ok := attrPtrClass[attr]; ok {
    194 			return class
    195 		}
    196 		return ClassUnknown
    197 
    198 	case formExprloc:
    199 		return ClassExprLoc
    200 
    201 	case formGnuRefAlt:
    202 		return ClassReferenceAlt
    203 
    204 	case formGnuStrpAlt:
    205 		return ClassStringAlt
    206 	}
    207 }
    208 
    209 // An entry is a sequence of attribute/value pairs.
    210 type Entry struct {
    211 	Offset   Offset // offset of Entry in DWARF info
    212 	Tag      Tag    // tag (kind of Entry)
    213 	Children bool   // whether Entry is followed by children
    214 	Field    []Field
    215 }
    216 
    217 // A Field is a single attribute/value pair in an Entry.
    218 //
    219 // A value can be one of several "attribute classes" defined by DWARF.
    220 // The Go types corresponding to each class are:
    221 //
    222 //    DWARF class       Go type        Class
    223 //    -----------       -------        -----
    224 //    address           uint64         ClassAddress
    225 //    block             []byte         ClassBlock
    226 //    constant          int64          ClassConstant
    227 //    flag              bool           ClassFlag
    228 //    reference
    229 //      to info         dwarf.Offset   ClassReference
    230 //      to type unit    uint64         ClassReferenceSig
    231 //    string            string         ClassString
    232 //    exprloc           []byte         ClassExprLoc
    233 //    lineptr           int64          ClassLinePtr
    234 //    loclistptr        int64          ClassLocListPtr
    235 //    macptr            int64          ClassMacPtr
    236 //    rangelistptr      int64          ClassRangeListPtr
    237 //
    238 // For unrecognized or vendor-defined attributes, Class may be
    239 // ClassUnknown.
    240 type Field struct {
    241 	Attr  Attr
    242 	Val   interface{}
    243 	Class Class
    244 }
    245 
    246 // A Class is the DWARF 4 class of an attribute value.
    247 //
    248 // In general, a given attribute's value may take on one of several
    249 // possible classes defined by DWARF, each of which leads to a
    250 // slightly different interpretation of the attribute.
    251 //
    252 // DWARF version 4 distinguishes attribute value classes more finely
    253 // than previous versions of DWARF. The reader will disambiguate
    254 // coarser classes from earlier versions of DWARF into the appropriate
    255 // DWARF 4 class. For example, DWARF 2 uses "constant" for constants
    256 // as well as all types of section offsets, but the reader will
    257 // canonicalize attributes in DWARF 2 files that refer to section
    258 // offsets to one of the Class*Ptr classes, even though these classes
    259 // were only defined in DWARF 3.
    260 type Class int
    261 
    262 const (
    263 	// ClassUnknown represents values of unknown DWARF class.
    264 	ClassUnknown Class = iota
    265 
    266 	// ClassAddress represents values of type uint64 that are
    267 	// addresses on the target machine.
    268 	ClassAddress
    269 
    270 	// ClassBlock represents values of type []byte whose
    271 	// interpretation depends on the attribute.
    272 	ClassBlock
    273 
    274 	// ClassConstant represents values of type int64 that are
    275 	// constants. The interpretation of this constant depends on
    276 	// the attribute.
    277 	ClassConstant
    278 
    279 	// ClassExprLoc represents values of type []byte that contain
    280 	// an encoded DWARF expression or location description.
    281 	ClassExprLoc
    282 
    283 	// ClassFlag represents values of type bool.
    284 	ClassFlag
    285 
    286 	// ClassLinePtr represents values that are an int64 offset
    287 	// into the "line" section.
    288 	ClassLinePtr
    289 
    290 	// ClassLocListPtr represents values that are an int64 offset
    291 	// into the "loclist" section.
    292 	ClassLocListPtr
    293 
    294 	// ClassMacPtr represents values that are an int64 offset into
    295 	// the "mac" section.
    296 	ClassMacPtr
    297 
    298 	// ClassMacPtr represents values that are an int64 offset into
    299 	// the "rangelist" section.
    300 	ClassRangeListPtr
    301 
    302 	// ClassReference represents values that are an Offset offset
    303 	// of an Entry in the info section (for use with Reader.Seek).
    304 	// The DWARF specification combines ClassReference and
    305 	// ClassReferenceSig into class "reference".
    306 	ClassReference
    307 
    308 	// ClassReferenceSig represents values that are a uint64 type
    309 	// signature referencing a type Entry.
    310 	ClassReferenceSig
    311 
    312 	// ClassString represents values that are strings. If the
    313 	// compilation unit specifies the AttrUseUTF8 flag (strongly
    314 	// recommended), the string value will be encoded in UTF-8.
    315 	// Otherwise, the encoding is unspecified.
    316 	ClassString
    317 
    318 	// ClassReferenceAlt represents values of type int64 that are
    319 	// an offset into the DWARF "info" section of an alternate
    320 	// object file.
    321 	ClassReferenceAlt
    322 
    323 	// ClassStringAlt represents values of type int64 that are an
    324 	// offset into the DWARF string section of an alternate object
    325 	// file.
    326 	ClassStringAlt
    327 )
    328 
    329 //go:generate stringer -type=Class
    330 
    331 func (i Class) GoString() string {
    332 	return "dwarf." + i.String()
    333 }
    334 
    335 // Val returns the value associated with attribute Attr in Entry,
    336 // or nil if there is no such attribute.
    337 //
    338 // A common idiom is to merge the check for nil return with
    339 // the check that the value has the expected dynamic type, as in:
    340 //	v, ok := e.Val(AttrSibling).(int64)
    341 //
    342 func (e *Entry) Val(a Attr) interface{} {
    343 	if f := e.AttrField(a); f != nil {
    344 		return f.Val
    345 	}
    346 	return nil
    347 }
    348 
    349 // AttrField returns the Field associated with attribute Attr in
    350 // Entry, or nil if there is no such attribute.
    351 func (e *Entry) AttrField(a Attr) *Field {
    352 	for i, f := range e.Field {
    353 		if f.Attr == a {
    354 			return &e.Field[i]
    355 		}
    356 	}
    357 	return nil
    358 }
    359 
    360 // An Offset represents the location of an Entry within the DWARF info.
    361 // (See Reader.Seek.)
    362 type Offset uint32
    363 
    364 // Entry reads a single entry from buf, decoding
    365 // according to the given abbreviation table.
    366 func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
    367 	off := b.off
    368 	id := uint32(b.uint())
    369 	if id == 0 {
    370 		return &Entry{}
    371 	}
    372 	a, ok := atab[id]
    373 	if !ok {
    374 		b.error("unknown abbreviation table index")
    375 		return nil
    376 	}
    377 	e := &Entry{
    378 		Offset:   off,
    379 		Tag:      a.tag,
    380 		Children: a.children,
    381 		Field:    make([]Field, len(a.field)),
    382 	}
    383 	for i := range e.Field {
    384 		e.Field[i].Attr = a.field[i].attr
    385 		e.Field[i].Class = a.field[i].class
    386 		fmt := a.field[i].fmt
    387 		if fmt == formIndirect {
    388 			fmt = format(b.uint())
    389 		}
    390 		var val interface{}
    391 		switch fmt {
    392 		default:
    393 			b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16))
    394 
    395 		// address
    396 		case formAddr:
    397 			val = b.addr()
    398 
    399 		// block
    400 		case formDwarfBlock1:
    401 			val = b.bytes(int(b.uint8()))
    402 		case formDwarfBlock2:
    403 			val = b.bytes(int(b.uint16()))
    404 		case formDwarfBlock4:
    405 			val = b.bytes(int(b.uint32()))
    406 		case formDwarfBlock:
    407 			val = b.bytes(int(b.uint()))
    408 
    409 		// constant
    410 		case formData1:
    411 			val = int64(b.uint8())
    412 		case formData2:
    413 			val = int64(b.uint16())
    414 		case formData4:
    415 			val = int64(b.uint32())
    416 		case formData8:
    417 			val = int64(b.uint64())
    418 		case formSdata:
    419 			val = int64(b.int())
    420 		case formUdata:
    421 			val = int64(b.uint())
    422 
    423 		// flag
    424 		case formFlag:
    425 			val = b.uint8() == 1
    426 		// New in DWARF 4.
    427 		case formFlagPresent:
    428 			// The attribute is implicitly indicated as present, and no value is
    429 			// encoded in the debugging information entry itself.
    430 			val = true
    431 
    432 		// reference to other entry
    433 		case formRefAddr:
    434 			vers := b.format.version()
    435 			if vers == 0 {
    436 				b.error("unknown version for DW_FORM_ref_addr")
    437 			} else if vers == 2 {
    438 				val = Offset(b.addr())
    439 			} else {
    440 				is64, known := b.format.dwarf64()
    441 				if !known {
    442 					b.error("unknown size for DW_FORM_ref_addr")
    443 				} else if is64 {
    444 					val = Offset(b.uint64())
    445 				} else {
    446 					val = Offset(b.uint32())
    447 				}
    448 			}
    449 		case formRef1:
    450 			val = Offset(b.uint8()) + ubase
    451 		case formRef2:
    452 			val = Offset(b.uint16()) + ubase
    453 		case formRef4:
    454 			val = Offset(b.uint32()) + ubase
    455 		case formRef8:
    456 			val = Offset(b.uint64()) + ubase
    457 		case formRefUdata:
    458 			val = Offset(b.uint()) + ubase
    459 
    460 		// string
    461 		case formString:
    462 			val = b.string()
    463 		case formStrp:
    464 			off := b.uint32() // offset into .debug_str
    465 			if b.err != nil {
    466 				return nil
    467 			}
    468 			b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
    469 			b1.skip(int(off))
    470 			val = b1.string()
    471 			if b1.err != nil {
    472 				b.err = b1.err
    473 				return nil
    474 			}
    475 
    476 		// lineptr, loclistptr, macptr, rangelistptr
    477 		// New in DWARF 4, but clang can generate them with -gdwarf-2.
    478 		// Section reference, replacing use of formData4 and formData8.
    479 		case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
    480 			is64, known := b.format.dwarf64()
    481 			if !known {
    482 				b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
    483 			} else if is64 {
    484 				val = int64(b.uint64())
    485 			} else {
    486 				val = int64(b.uint32())
    487 			}
    488 
    489 		// exprloc
    490 		// New in DWARF 4.
    491 		case formExprloc:
    492 			val = b.bytes(int(b.uint()))
    493 
    494 		// reference
    495 		// New in DWARF 4.
    496 		case formRefSig8:
    497 			// 64-bit type signature.
    498 			val = b.uint64()
    499 		}
    500 		e.Field[i].Val = val
    501 	}
    502 	if b.err != nil {
    503 		return nil
    504 	}
    505 	return e
    506 }
    507 
    508 // A Reader allows reading Entry structures from a DWARF ``info'' section.
    509 // The Entry structures are arranged in a tree. The Reader's Next function
    510 // return successive entries from a pre-order traversal of the tree.
    511 // If an entry has children, its Children field will be true, and the children
    512 // follow, terminated by an Entry with Tag 0.
    513 type Reader struct {
    514 	b            buf
    515 	d            *Data
    516 	err          error
    517 	unit         int
    518 	lastChildren bool   // .Children of last entry returned by Next
    519 	lastSibling  Offset // .Val(AttrSibling) of last entry returned by Next
    520 }
    521 
    522 // Reader returns a new Reader for Data.
    523 // The reader is positioned at byte offset 0 in the DWARF ``info'' section.
    524 func (d *Data) Reader() *Reader {
    525 	r := &Reader{d: d}
    526 	r.Seek(0)
    527 	return r
    528 }
    529 
    530 // AddressSize returns the size in bytes of addresses in the current compilation
    531 // unit.
    532 func (r *Reader) AddressSize() int {
    533 	return r.d.unit[r.unit].asize
    534 }
    535 
    536 // Seek positions the Reader at offset off in the encoded entry stream.
    537 // Offset 0 can be used to denote the first entry.
    538 func (r *Reader) Seek(off Offset) {
    539 	d := r.d
    540 	r.err = nil
    541 	r.lastChildren = false
    542 	if off == 0 {
    543 		if len(d.unit) == 0 {
    544 			return
    545 		}
    546 		u := &d.unit[0]
    547 		r.unit = 0
    548 		r.b = makeBuf(r.d, u, "info", u.off, u.data)
    549 		return
    550 	}
    551 
    552 	i := d.offsetToUnit(off)
    553 	if i == -1 {
    554 		r.err = errors.New("offset out of range")
    555 		return
    556 	}
    557 	u := &d.unit[i]
    558 	r.unit = i
    559 	r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
    560 }
    561 
    562 // maybeNextUnit advances to the next unit if this one is finished.
    563 func (r *Reader) maybeNextUnit() {
    564 	for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
    565 		r.unit++
    566 		u := &r.d.unit[r.unit]
    567 		r.b = makeBuf(r.d, u, "info", u.off, u.data)
    568 	}
    569 }
    570 
    571 // Next reads the next entry from the encoded entry stream.
    572 // It returns nil, nil when it reaches the end of the section.
    573 // It returns an error if the current offset is invalid or the data at the
    574 // offset cannot be decoded as a valid Entry.
    575 func (r *Reader) Next() (*Entry, error) {
    576 	if r.err != nil {
    577 		return nil, r.err
    578 	}
    579 	r.maybeNextUnit()
    580 	if len(r.b.data) == 0 {
    581 		return nil, nil
    582 	}
    583 	u := &r.d.unit[r.unit]
    584 	e := r.b.entry(u.atable, u.base)
    585 	if r.b.err != nil {
    586 		r.err = r.b.err
    587 		return nil, r.err
    588 	}
    589 	if e != nil {
    590 		r.lastChildren = e.Children
    591 		if r.lastChildren {
    592 			r.lastSibling, _ = e.Val(AttrSibling).(Offset)
    593 		}
    594 	} else {
    595 		r.lastChildren = false
    596 	}
    597 	return e, nil
    598 }
    599 
    600 // SkipChildren skips over the child entries associated with
    601 // the last Entry returned by Next. If that Entry did not have
    602 // children or Next has not been called, SkipChildren is a no-op.
    603 func (r *Reader) SkipChildren() {
    604 	if r.err != nil || !r.lastChildren {
    605 		return
    606 	}
    607 
    608 	// If the last entry had a sibling attribute,
    609 	// that attribute gives the offset of the next
    610 	// sibling, so we can avoid decoding the
    611 	// child subtrees.
    612 	if r.lastSibling >= r.b.off {
    613 		r.Seek(r.lastSibling)
    614 		return
    615 	}
    616 
    617 	for {
    618 		e, err := r.Next()
    619 		if err != nil || e == nil || e.Tag == 0 {
    620 			break
    621 		}
    622 		if e.Children {
    623 			r.SkipChildren()
    624 		}
    625 	}
    626 }
    627 
    628 // clone returns a copy of the reader. This is used by the typeReader
    629 // interface.
    630 func (r *Reader) clone() typeReader {
    631 	return r.d.Reader()
    632 }
    633 
    634 // offset returns the current buffer offset. This is used by the
    635 // typeReader interface.
    636 func (r *Reader) offset() Offset {
    637 	return r.b.off
    638 }
    639 
    640 // SeekPC returns the Entry for the compilation unit that includes pc,
    641 // and positions the reader to read the children of that unit.  If pc
    642 // is not covered by any unit, SeekPC returns ErrUnknownPC and the
    643 // position of the reader is undefined.
    644 //
    645 // Because compilation units can describe multiple regions of the
    646 // executable, in the worst case SeekPC must search through all the
    647 // ranges in all the compilation units. Each call to SeekPC starts the
    648 // search at the compilation unit of the last call, so in general
    649 // looking up a series of PCs will be faster if they are sorted. If
    650 // the caller wishes to do repeated fast PC lookups, it should build
    651 // an appropriate index using the Ranges method.
    652 func (r *Reader) SeekPC(pc uint64) (*Entry, error) {
    653 	unit := r.unit
    654 	for i := 0; i < len(r.d.unit); i++ {
    655 		if unit >= len(r.d.unit) {
    656 			unit = 0
    657 		}
    658 		r.err = nil
    659 		r.lastChildren = false
    660 		r.unit = unit
    661 		u := &r.d.unit[unit]
    662 		r.b = makeBuf(r.d, u, "info", u.off, u.data)
    663 		e, err := r.Next()
    664 		if err != nil {
    665 			return nil, err
    666 		}
    667 		ranges, err := r.d.Ranges(e)
    668 		if err != nil {
    669 			return nil, err
    670 		}
    671 		for _, pcs := range ranges {
    672 			if pcs[0] <= pc && pc < pcs[1] {
    673 				return e, nil
    674 			}
    675 		}
    676 		unit++
    677 	}
    678 	return nil, ErrUnknownPC
    679 }
    680 
    681 // Ranges returns the PC ranges covered by e, a slice of [low,high) pairs.
    682 // Only some entry types, such as TagCompileUnit or TagSubprogram, have PC
    683 // ranges; for others, this will return nil with no error.
    684 func (d *Data) Ranges(e *Entry) ([][2]uint64, error) {
    685 	var ret [][2]uint64
    686 
    687 	low, lowOK := e.Val(AttrLowpc).(uint64)
    688 
    689 	var high uint64
    690 	var highOK bool
    691 	highField := e.AttrField(AttrHighpc)
    692 	if highField != nil {
    693 		switch highField.Class {
    694 		case ClassAddress:
    695 			high, highOK = highField.Val.(uint64)
    696 		case ClassConstant:
    697 			off, ok := highField.Val.(int64)
    698 			if ok {
    699 				high = low + uint64(off)
    700 				highOK = true
    701 			}
    702 		}
    703 	}
    704 
    705 	if lowOK && highOK {
    706 		ret = append(ret, [2]uint64{low, high})
    707 	}
    708 
    709 	ranges, rangesOK := e.Val(AttrRanges).(int64)
    710 	if rangesOK && d.ranges != nil {
    711 		// The initial base address is the lowpc attribute
    712 		// of the enclosing compilation unit.
    713 		// Although DWARF specifies the lowpc attribute,
    714 		// comments in gdb/dwarf2read.c say that some versions
    715 		// of GCC use the entrypc attribute, so we check that too.
    716 		var cu *Entry
    717 		if e.Tag == TagCompileUnit {
    718 			cu = e
    719 		} else {
    720 			i := d.offsetToUnit(e.Offset)
    721 			if i == -1 {
    722 				return nil, errors.New("no unit for entry")
    723 			}
    724 			u := &d.unit[i]
    725 			b := makeBuf(d, u, "info", u.off, u.data)
    726 			cu = b.entry(u.atable, u.base)
    727 			if b.err != nil {
    728 				return nil, b.err
    729 			}
    730 		}
    731 
    732 		var base uint64
    733 		if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK {
    734 			base = cuEntry
    735 		} else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK {
    736 			base = cuLow
    737 		}
    738 
    739 		u := &d.unit[d.offsetToUnit(e.Offset)]
    740 		buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:])
    741 		for len(buf.data) > 0 {
    742 			low = buf.addr()
    743 			high = buf.addr()
    744 
    745 			if low == 0 && high == 0 {
    746 				break
    747 			}
    748 
    749 			if low == ^uint64(0)>>uint((8-u.addrsize())*8) {
    750 				base = high
    751 			} else {
    752 				ret = append(ret, [2]uint64{base + low, base + high})
    753 			}
    754 		}
    755 	}
    756 
    757 	return ret, nil
    758 }
    759