12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211 |
- // 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 (
- "encoding/binary"
- "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
- 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 (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) {
- if m, ok := d.abbrevCache[off]; ok {
- return m, nil
- }
- data := d.abbrev
- if off > uint64(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
- }
- if format(fmt) == formImplicitConst {
- b1.int()
- }
- 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())
- a.field[i].class = formToClass(a.field[i].fmt, a.field[i].attr, vers, &b)
- if a.field[i].fmt == formImplicitConst {
- a.field[i].val = b.int()
- }
- }
- b.uint()
- b.uint()
- m[id] = a
- }
- if b.err != nil {
- return nil, b.err
- }
- d.abbrevCache[off] = m
- return m, 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(form format, attr Attr, vers int, b *buf) Class {
- switch form {
- default:
- b.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[attr] {
- 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 class, ok := attrPtrClass[attr]; vers < 4 && ok {
- return class
- }
- 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 class, ok := attrPtrClass[attr]; ok {
- return class
- }
- 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 (i Class) GoString() string {
- return "dwarf." + i.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 (e *Entry) Val(a Attr) any {
- if f := e.AttrField(a); f != nil {
- return f.Val
- }
- return nil
- }
- // AttrField returns the Field associated with attribute Attr in
- // Entry, or nil if there is no such attribute.
- func (e *Entry) AttrField(a Attr) *Field {
- for i, f := range e.Field {
- if f.Attr == a {
- return &e.Field[i]
- }
- }
- 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(cu *Entry, atab abbrevTable, ubase Offset, vers int) *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)),
- }
- // If we are currently parsing the compilation unit,
- // we can't evaluate Addrx or Strx until we've seen the
- // relevant base entry.
- type delayed struct {
- idx int
- off uint64
- fmt format
- }
- var delay []delayed
- resolveStrx := func(strBase, off uint64) string {
- off += strBase
- if uint64(int(off)) != off {
- b.error("DW_FORM_strx offset out of range")
- }
- b1 := makeBuf(b.dwarf, b.format, "str_offsets", 0, b.dwarf.strOffsets)
- b1.skip(int(off))
- is64, _ := b.format.dwarf64()
- if is64 {
- off = b1.uint64()
- } else {
- off = uint64(b1.uint32())
- }
- if b1.err != nil {
- b.err = b1.err
- return ""
- }
- if uint64(int(off)) != off {
- b.error("DW_FORM_strx indirect offset out of range")
- }
- b1 = makeBuf(b.dwarf, b.format, "str", 0, b.dwarf.str)
- b1.skip(int(off))
- val := b1.string()
- if b1.err != nil {
- b.err = b1.err
- }
- return val
- }
- resolveRnglistx := func(rnglistsBase, off uint64) uint64 {
- is64, _ := b.format.dwarf64()
- if is64 {
- off *= 8
- } else {
- off *= 4
- }
- off += rnglistsBase
- if uint64(int(off)) != off {
- b.error("DW_FORM_rnglistx offset out of range")
- }
- b1 := makeBuf(b.dwarf, b.format, "rnglists", 0, b.dwarf.rngLists)
- b1.skip(int(off))
- if is64 {
- off = b1.uint64()
- } else {
- off = uint64(b1.uint32())
- }
- if b1.err != nil {
- b.err = b1.err
- return 0
- }
- if uint64(int(off)) != off {
- b.error("DW_FORM_rnglistx indirect offset out of range")
- }
- return rnglistsBase + off
- }
- for i := range e.Field {
- e.Field[i].Attr = a.field[i].attr
- e.Field[i].Class = a.field[i].class
- fmt := a.field[i].fmt
- if fmt == formIndirect {
- fmt = format(b.uint())
- e.Field[i].Class = formToClass(fmt, a.field[i].attr, vers, b)
- }
- var val any
- switch fmt {
- default:
- b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16))
- // address
- case formAddr:
- val = b.addr()
- case formAddrx, formAddrx1, formAddrx2, formAddrx3, formAddrx4:
- var off uint64
- switch fmt {
- case formAddrx:
- off = b.uint()
- case formAddrx1:
- off = uint64(b.uint8())
- case formAddrx2:
- off = uint64(b.uint16())
- case formAddrx3:
- off = uint64(b.uint24())
- case formAddrx4:
- off = uint64(b.uint32())
- }
- if b.dwarf.addr == nil {
- b.error("DW_FORM_addrx with no .debug_addr section")
- }
- if b.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 addrBase int64
- if cu != nil {
- addrBase, _ = cu.Val(AttrAddrBase).(int64)
- } else if a.tag == TagCompileUnit {
- delay = append(delay, delayed{i, off, formAddrx})
- break
- }
- var err error
- val, err = b.dwarf.debugAddr(b.format, uint64(addrBase), off)
- if err != nil {
- if b.err == nil {
- b.err = err
- }
- return nil
- }
- // 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 formData16:
- val = b.bytes(16)
- case formSdata:
- val = int64(b.int())
- case formUdata:
- val = int64(b.uint())
- case formImplicitConst:
- val = a.field[i].val
- // 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, formLineStrp:
- var off uint64 // offset into .debug_str
- is64, known := b.format.dwarf64()
- if !known {
- b.error("unknown size for DW_FORM_strp/line_strp")
- } else if is64 {
- off = b.uint64()
- } else {
- off = uint64(b.uint32())
- }
- if uint64(int(off)) != off {
- b.error("DW_FORM_strp/line_strp offset out of range")
- }
- if b.err != nil {
- return nil
- }
- var b1 buf
- if fmt == formStrp {
- b1 = makeBuf(b.dwarf, b.format, "str", 0, b.dwarf.str)
- } else {
- if len(b.dwarf.lineStr) == 0 {
- b.error("DW_FORM_line_strp with no .debug_line_str section")
- return nil
- }
- b1 = makeBuf(b.dwarf, b.format, "line_str", 0, b.dwarf.lineStr)
- }
- b1.skip(int(off))
- val = b1.string()
- if b1.err != nil {
- b.err = b1.err
- return nil
- }
- case formStrx, formStrx1, formStrx2, formStrx3, formStrx4:
- var off uint64
- switch fmt {
- case formStrx:
- off = b.uint()
- case formStrx1:
- off = uint64(b.uint8())
- case formStrx2:
- off = uint64(b.uint16())
- case formStrx3:
- off = uint64(b.uint24())
- case formStrx4:
- off = uint64(b.uint32())
- }
- if len(b.dwarf.strOffsets) == 0 {
- b.error("DW_FORM_strx with no .debug_str_offsets section")
- }
- is64, known := b.format.dwarf64()
- if !known {
- b.error("unknown offset size for DW_FORM_strx")
- }
- if b.err != nil {
- return nil
- }
- if is64 {
- off *= 8
- } else {
- off *= 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 strBase int64
- if cu != nil {
- strBase, _ = cu.Val(AttrStrOffsetsBase).(int64)
- } else if a.tag == TagCompileUnit {
- delay = append(delay, delayed{i, off, formStrx})
- break
- }
- val = resolveStrx(uint64(strBase), off)
- case formStrpSup:
- is64, known := b.format.dwarf64()
- if !known {
- b.error("unknown size for DW_FORM_strp_sup")
- } else if is64 {
- val = b.uint64()
- } else {
- val = b.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:
- 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()
- case formRefSup4:
- val = b.uint32()
- case formRefSup8:
- val = b.uint64()
- // loclist
- case formLoclistx:
- val = b.uint()
- // rnglist
- case formRnglistx:
- off := b.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 rnglistsBase int64
- if cu != nil {
- rnglistsBase, _ = cu.Val(AttrRnglistsBase).(int64)
- } else if a.tag == TagCompileUnit {
- delay = append(delay, delayed{i, off, formRnglistx})
- break
- }
- val = resolveRnglistx(uint64(rnglistsBase), off)
- }
- e.Field[i].Val = val
- }
- if b.err != nil {
- return nil
- }
- for _, del := range delay {
- switch del.fmt {
- case formAddrx:
- addrBase, _ := e.Val(AttrAddrBase).(int64)
- val, err := b.dwarf.debugAddr(b.format, uint64(addrBase), del.off)
- if err != nil {
- b.err = err
- return nil
- }
- e.Field[del.idx].Val = val
- case formStrx:
- strBase, _ := e.Val(AttrStrOffsetsBase).(int64)
- e.Field[del.idx].Val = resolveStrx(uint64(strBase), del.off)
- if b.err != nil {
- return nil
- }
- case formRnglistx:
- rnglistsBase, _ := e.Val(AttrRnglistsBase).(int64)
- e.Field[del.idx].Val = resolveRnglistx(uint64(rnglistsBase), del.off)
- 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
- 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 (d *Data) Reader() *Reader {
- r := &Reader{d: d}
- r.Seek(0)
- return r
- }
- // AddressSize returns the size in bytes of addresses in the current compilation
- // unit.
- func (r *Reader) AddressSize() int {
- return r.d.unit[r.unit].asize
- }
- // ByteOrder returns the byte order in the current compilation unit.
- func (r *Reader) ByteOrder() binary.ByteOrder {
- return r.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 (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)
- r.cu = nil
- return
- }
- i := d.offsetToUnit(off)
- if i == -1 {
- r.err = errors.New("offset out of range")
- return
- }
- if i != r.unit {
- r.cu = nil
- }
- u := &d.unit[i]
- r.unit = i
- r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
- }
- // 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.nextUnit()
- }
- }
- // nextUnit advances to the next unit.
- func (r *Reader) nextUnit() {
- r.unit++
- u := &r.d.unit[r.unit]
- r.b = makeBuf(r.d, u, "info", u.off, u.data)
- r.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 (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(r.cu, u.atable, u.base, u.vers)
- if r.b.err != nil {
- r.err = r.b.err
- return nil, r.err
- }
- r.lastUnit = false
- if e != nil {
- r.lastChildren = e.Children
- if r.lastChildren {
- r.lastSibling, _ = e.Val(AttrSibling).(Offset)
- }
- if e.Tag == TagCompileUnit || e.Tag == TagPartialUnit {
- r.lastUnit = true
- r.cu = e
- }
- } 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
- }
- if r.lastUnit && r.unit+1 < len(r.d.unit) {
- r.nextUnit()
- 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
- }
- // 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 (r *Reader) SeekPC(pc uint64) (*Entry, error) {
- unit := r.unit
- for i := 0; i < len(r.d.unit); i++ {
- if unit >= len(r.d.unit) {
- unit = 0
- }
- r.err = nil
- r.lastChildren = false
- r.unit = unit
- r.cu = nil
- u := &r.d.unit[unit]
- r.b = makeBuf(r.d, u, "info", u.off, u.data)
- e, err := r.Next()
- if err != nil {
- return nil, err
- }
- ranges, err := r.d.Ranges(e)
- if err != nil {
- return nil, err
- }
- for _, pcs := range ranges {
- if pcs[0] <= pc && pc < pcs[1] {
- return e, nil
- }
- }
- unit++
- }
- 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 (d *Data) Ranges(e *Entry) ([][2]uint64, error) {
- var ret [][2]uint64
- low, lowOK := e.Val(AttrLowpc).(uint64)
- var high uint64
- var highOK bool
- highField := e.AttrField(AttrHighpc)
- if highField != nil {
- switch highField.Class {
- case ClassAddress:
- high, highOK = highField.Val.(uint64)
- case ClassConstant:
- off, ok := highField.Val.(int64)
- if ok {
- high = low + uint64(off)
- highOK = true
- }
- }
- }
- if lowOK && highOK {
- ret = append(ret, [2]uint64{low, high})
- }
- var u *unit
- if uidx := d.offsetToUnit(e.Offset); uidx >= 0 && uidx < len(d.unit) {
- u = &d.unit[uidx]
- }
- if u != nil && u.vers >= 5 && d.rngLists != nil {
- // DWARF version 5 and later
- field := e.AttrField(AttrRanges)
- if field == nil {
- return ret, nil
- }
- switch field.Class {
- case ClassRangeListPtr:
- ranges, rangesOK := field.Val.(int64)
- if !rangesOK {
- return ret, nil
- }
- cu, base, err := d.baseAddressForEntry(e)
- if err != nil {
- return nil, err
- }
- return d.dwarf5Ranges(u, cu, base, ranges, ret)
- case ClassRngList:
- rnglist, ok := field.Val.(uint64)
- if !ok {
- return ret, nil
- }
- cu, base, err := d.baseAddressForEntry(e)
- if err != nil {
- return nil, err
- }
- return d.dwarf5Ranges(u, cu, base, int64(rnglist), ret)
- default:
- return ret, nil
- }
- }
- // DWARF version 2 through 4
- ranges, rangesOK := e.Val(AttrRanges).(int64)
- if rangesOK && d.ranges != nil {
- _, base, err := d.baseAddressForEntry(e)
- if err != nil {
- return nil, err
- }
- return d.dwarf2Ranges(u, base, ranges, ret)
- }
- return ret, 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 (d *Data) baseAddressForEntry(e *Entry) (*Entry, uint64, error) {
- var cu *Entry
- if e.Tag == TagCompileUnit {
- cu = e
- } else {
- i := d.offsetToUnit(e.Offset)
- if i == -1 {
- return nil, 0, errors.New("no unit for entry")
- }
- u := &d.unit[i]
- b := makeBuf(d, u, "info", u.off, u.data)
- cu = b.entry(nil, u.atable, u.base, u.vers)
- if b.err != nil {
- return nil, 0, b.err
- }
- }
- if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK {
- return cu, cuEntry, nil
- } else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK {
- return cu, cuLow, nil
- }
- return cu, 0, nil
- }
- func (d *Data) dwarf2Ranges(u *unit, base uint64, ranges int64, ret [][2]uint64) ([][2]uint64, error) {
- buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:])
- for len(buf.data) > 0 {
- low := buf.addr()
- high := buf.addr()
- if low == 0 && high == 0 {
- break
- }
- if low == ^uint64(0)>>uint((8-u.addrsize())*8) {
- base = high
- } else {
- ret = append(ret, [2]uint64{base + low, base + high})
- }
- }
- return ret, nil
- }
- // dwarf5Ranges interpets a debug_rnglists sequence, see DWARFv5 section
- // 2.17.3 (page 53).
- func (d *Data) dwarf5Ranges(u *unit, cu *Entry, base uint64, ranges int64, ret [][2]uint64) ([][2]uint64, error) {
- var addrBase int64
- if cu != nil {
- addrBase, _ = cu.Val(AttrAddrBase).(int64)
- }
- buf := makeBuf(d, u, "rnglists", 0, d.rngLists)
- buf.skip(int(ranges))
- for {
- opcode := buf.uint8()
- switch opcode {
- case rleEndOfList:
- if buf.err != nil {
- return nil, buf.err
- }
- return ret, nil
- case rleBaseAddressx:
- baseIdx := buf.uint()
- var err error
- base, err = d.debugAddr(u, uint64(addrBase), baseIdx)
- if err != nil {
- return nil, err
- }
- case rleStartxEndx:
- startIdx := buf.uint()
- endIdx := buf.uint()
- start, err := d.debugAddr(u, uint64(addrBase), startIdx)
- if err != nil {
- return nil, err
- }
- end, err := d.debugAddr(u, uint64(addrBase), endIdx)
- if err != nil {
- return nil, err
- }
- ret = append(ret, [2]uint64{start, end})
- case rleStartxLength:
- startIdx := buf.uint()
- len := buf.uint()
- start, err := d.debugAddr(u, uint64(addrBase), startIdx)
- if err != nil {
- return nil, err
- }
- ret = append(ret, [2]uint64{start, start + len})
- case rleOffsetPair:
- off1 := buf.uint()
- off2 := buf.uint()
- ret = append(ret, [2]uint64{base + off1, base + off2})
- case rleBaseAddress:
- base = buf.addr()
- case rleStartEnd:
- start := buf.addr()
- end := buf.addr()
- ret = append(ret, [2]uint64{start, end})
- case rleStartLength:
- start := buf.addr()
- len := buf.uint()
- ret = append(ret, [2]uint64{start, start + len})
- }
- }
- }
- // debugAddr returns the address at idx in debug_addr
- func (d *Data) debugAddr(format dataFormat, addrBase, idx uint64) (uint64, error) {
- off := idx*uint64(format.addrsize()) + addrBase
- if uint64(int(off)) != off {
- return 0, errors.New("offset out of range")
- }
- b := makeBuf(d, format, "addr", 0, d.addr)
- b.skip(int(off))
- val := b.addr()
- if b.err != nil {
- return 0, b.err
- }
- return val, nil
- }
|