...
Run Format

Source file src/debug/dwarf/entry.go

Documentation: debug/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  			var off uint64 // offset into .debug_str
   465  			is64, known := b.format.dwarf64()
   466  			if !known {
   467  				b.error("unknown size for DW_FORM_strp")
   468  			} else if is64 {
   469  				off = b.uint64()
   470  			} else {
   471  				off = uint64(b.uint32())
   472  			}
   473  			if uint64(int(off)) != off {
   474  				b.error("DW_FORM_strp offset out of range")
   475  			}
   476  			if b.err != nil {
   477  				return nil
   478  			}
   479  			b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
   480  			b1.skip(int(off))
   481  			val = b1.string()
   482  			if b1.err != nil {
   483  				b.err = b1.err
   484  				return nil
   485  			}
   486  
   487  		// lineptr, loclistptr, macptr, rangelistptr
   488  		// New in DWARF 4, but clang can generate them with -gdwarf-2.
   489  		// Section reference, replacing use of formData4 and formData8.
   490  		case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
   491  			is64, known := b.format.dwarf64()
   492  			if !known {
   493  				b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
   494  			} else if is64 {
   495  				val = int64(b.uint64())
   496  			} else {
   497  				val = int64(b.uint32())
   498  			}
   499  
   500  		// exprloc
   501  		// New in DWARF 4.
   502  		case formExprloc:
   503  			val = b.bytes(int(b.uint()))
   504  
   505  		// reference
   506  		// New in DWARF 4.
   507  		case formRefSig8:
   508  			// 64-bit type signature.
   509  			val = b.uint64()
   510  		}
   511  		e.Field[i].Val = val
   512  	}
   513  	if b.err != nil {
   514  		return nil
   515  	}
   516  	return e
   517  }
   518  
   519  // A Reader allows reading Entry structures from a DWARF ``info'' section.
   520  // The Entry structures are arranged in a tree. The Reader's Next function
   521  // return successive entries from a pre-order traversal of the tree.
   522  // If an entry has children, its Children field will be true, and the children
   523  // follow, terminated by an Entry with Tag 0.
   524  type Reader struct {
   525  	b            buf
   526  	d            *Data
   527  	err          error
   528  	unit         int
   529  	lastChildren bool   // .Children of last entry returned by Next
   530  	lastSibling  Offset // .Val(AttrSibling) of last entry returned by Next
   531  }
   532  
   533  // Reader returns a new Reader for Data.
   534  // The reader is positioned at byte offset 0 in the DWARF ``info'' section.
   535  func (d *Data) Reader() *Reader {
   536  	r := &Reader{d: d}
   537  	r.Seek(0)
   538  	return r
   539  }
   540  
   541  // AddressSize returns the size in bytes of addresses in the current compilation
   542  // unit.
   543  func (r *Reader) AddressSize() int {
   544  	return r.d.unit[r.unit].asize
   545  }
   546  
   547  // Seek positions the Reader at offset off in the encoded entry stream.
   548  // Offset 0 can be used to denote the first entry.
   549  func (r *Reader) Seek(off Offset) {
   550  	d := r.d
   551  	r.err = nil
   552  	r.lastChildren = false
   553  	if off == 0 {
   554  		if len(d.unit) == 0 {
   555  			return
   556  		}
   557  		u := &d.unit[0]
   558  		r.unit = 0
   559  		r.b = makeBuf(r.d, u, "info", u.off, u.data)
   560  		return
   561  	}
   562  
   563  	i := d.offsetToUnit(off)
   564  	if i == -1 {
   565  		r.err = errors.New("offset out of range")
   566  		return
   567  	}
   568  	u := &d.unit[i]
   569  	r.unit = i
   570  	r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
   571  }
   572  
   573  // maybeNextUnit advances to the next unit if this one is finished.
   574  func (r *Reader) maybeNextUnit() {
   575  	for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
   576  		r.unit++
   577  		u := &r.d.unit[r.unit]
   578  		r.b = makeBuf(r.d, u, "info", u.off, u.data)
   579  	}
   580  }
   581  
   582  // Next reads the next entry from the encoded entry stream.
   583  // It returns nil, nil when it reaches the end of the section.
   584  // It returns an error if the current offset is invalid or the data at the
   585  // offset cannot be decoded as a valid Entry.
   586  func (r *Reader) Next() (*Entry, error) {
   587  	if r.err != nil {
   588  		return nil, r.err
   589  	}
   590  	r.maybeNextUnit()
   591  	if len(r.b.data) == 0 {
   592  		return nil, nil
   593  	}
   594  	u := &r.d.unit[r.unit]
   595  	e := r.b.entry(u.atable, u.base)
   596  	if r.b.err != nil {
   597  		r.err = r.b.err
   598  		return nil, r.err
   599  	}
   600  	if e != nil {
   601  		r.lastChildren = e.Children
   602  		if r.lastChildren {
   603  			r.lastSibling, _ = e.Val(AttrSibling).(Offset)
   604  		}
   605  	} else {
   606  		r.lastChildren = false
   607  	}
   608  	return e, nil
   609  }
   610  
   611  // SkipChildren skips over the child entries associated with
   612  // the last Entry returned by Next. If that Entry did not have
   613  // children or Next has not been called, SkipChildren is a no-op.
   614  func (r *Reader) SkipChildren() {
   615  	if r.err != nil || !r.lastChildren {
   616  		return
   617  	}
   618  
   619  	// If the last entry had a sibling attribute,
   620  	// that attribute gives the offset of the next
   621  	// sibling, so we can avoid decoding the
   622  	// child subtrees.
   623  	if r.lastSibling >= r.b.off {
   624  		r.Seek(r.lastSibling)
   625  		return
   626  	}
   627  
   628  	for {
   629  		e, err := r.Next()
   630  		if err != nil || e == nil || e.Tag == 0 {
   631  			break
   632  		}
   633  		if e.Children {
   634  			r.SkipChildren()
   635  		}
   636  	}
   637  }
   638  
   639  // clone returns a copy of the reader. This is used by the typeReader
   640  // interface.
   641  func (r *Reader) clone() typeReader {
   642  	return r.d.Reader()
   643  }
   644  
   645  // offset returns the current buffer offset. This is used by the
   646  // typeReader interface.
   647  func (r *Reader) offset() Offset {
   648  	return r.b.off
   649  }
   650  
   651  // SeekPC returns the Entry for the compilation unit that includes pc,
   652  // and positions the reader to read the children of that unit.  If pc
   653  // is not covered by any unit, SeekPC returns ErrUnknownPC and the
   654  // position of the reader is undefined.
   655  //
   656  // Because compilation units can describe multiple regions of the
   657  // executable, in the worst case SeekPC must search through all the
   658  // ranges in all the compilation units. Each call to SeekPC starts the
   659  // search at the compilation unit of the last call, so in general
   660  // looking up a series of PCs will be faster if they are sorted. If
   661  // the caller wishes to do repeated fast PC lookups, it should build
   662  // an appropriate index using the Ranges method.
   663  func (r *Reader) SeekPC(pc uint64) (*Entry, error) {
   664  	unit := r.unit
   665  	for i := 0; i < len(r.d.unit); i++ {
   666  		if unit >= len(r.d.unit) {
   667  			unit = 0
   668  		}
   669  		r.err = nil
   670  		r.lastChildren = false
   671  		r.unit = unit
   672  		u := &r.d.unit[unit]
   673  		r.b = makeBuf(r.d, u, "info", u.off, u.data)
   674  		e, err := r.Next()
   675  		if err != nil {
   676  			return nil, err
   677  		}
   678  		ranges, err := r.d.Ranges(e)
   679  		if err != nil {
   680  			return nil, err
   681  		}
   682  		for _, pcs := range ranges {
   683  			if pcs[0] <= pc && pc < pcs[1] {
   684  				return e, nil
   685  			}
   686  		}
   687  		unit++
   688  	}
   689  	return nil, ErrUnknownPC
   690  }
   691  
   692  // Ranges returns the PC ranges covered by e, a slice of [low,high) pairs.
   693  // Only some entry types, such as TagCompileUnit or TagSubprogram, have PC
   694  // ranges; for others, this will return nil with no error.
   695  func (d *Data) Ranges(e *Entry) ([][2]uint64, error) {
   696  	var ret [][2]uint64
   697  
   698  	low, lowOK := e.Val(AttrLowpc).(uint64)
   699  
   700  	var high uint64
   701  	var highOK bool
   702  	highField := e.AttrField(AttrHighpc)
   703  	if highField != nil {
   704  		switch highField.Class {
   705  		case ClassAddress:
   706  			high, highOK = highField.Val.(uint64)
   707  		case ClassConstant:
   708  			off, ok := highField.Val.(int64)
   709  			if ok {
   710  				high = low + uint64(off)
   711  				highOK = true
   712  			}
   713  		}
   714  	}
   715  
   716  	if lowOK && highOK {
   717  		ret = append(ret, [2]uint64{low, high})
   718  	}
   719  
   720  	ranges, rangesOK := e.Val(AttrRanges).(int64)
   721  	if rangesOK && d.ranges != nil {
   722  		// The initial base address is the lowpc attribute
   723  		// of the enclosing compilation unit.
   724  		// Although DWARF specifies the lowpc attribute,
   725  		// comments in gdb/dwarf2read.c say that some versions
   726  		// of GCC use the entrypc attribute, so we check that too.
   727  		var cu *Entry
   728  		if e.Tag == TagCompileUnit {
   729  			cu = e
   730  		} else {
   731  			i := d.offsetToUnit(e.Offset)
   732  			if i == -1 {
   733  				return nil, errors.New("no unit for entry")
   734  			}
   735  			u := &d.unit[i]
   736  			b := makeBuf(d, u, "info", u.off, u.data)
   737  			cu = b.entry(u.atable, u.base)
   738  			if b.err != nil {
   739  				return nil, b.err
   740  			}
   741  		}
   742  
   743  		var base uint64
   744  		if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK {
   745  			base = cuEntry
   746  		} else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK {
   747  			base = cuLow
   748  		}
   749  
   750  		u := &d.unit[d.offsetToUnit(e.Offset)]
   751  		buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:])
   752  		for len(buf.data) > 0 {
   753  			low = buf.addr()
   754  			high = buf.addr()
   755  
   756  			if low == 0 && high == 0 {
   757  				break
   758  			}
   759  
   760  			if low == ^uint64(0)>>uint((8-u.addrsize())*8) {
   761  				base = high
   762  			} else {
   763  				ret = append(ret, [2]uint64{base + low, base + high})
   764  			}
   765  		}
   766  	}
   767  
   768  	return ret, nil
   769  }
   770  

View as plain text