| |
| |
| |
|
|
| |
| |
| |
| |
| |
|
|
| package dwarf |
|
|
| import ( |
| "encoding/binary" |
| "errors" |
| "fmt" |
| "strconv" |
| ) |
|
|
| |
| type abbrev struct { |
| tag Tag |
| children bool |
| field []afield |
| } |
|
|
| type afield struct { |
| attr Attr |
| fmt format |
| class Class |
| val int64 |
| } |
|
|
| |
| type abbrevTable map[uint32]abbrev |
|
|
| |
| |
| 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) |
|
|
| |
| |
| m := make(abbrevTable) |
| for { |
| |
| id := uint32(b.uint()) |
| if id == 0 { |
| break |
| } |
|
|
| |
| n := 0 |
| b1 := 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 |
| } |
|
|
| |
| 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 |
| } |
|
|
| |
| |
| |
| 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, |
| } |
|
|
| |
| |
| 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, |
| |
| AttrStrOffsetsBase: ClassStrOffsetsPtr, |
| AttrAddrBase: ClassAddrPtr, |
| AttrRnglistsBase: ClassRngListsPtr, |
| AttrLoclistsBase: ClassLocListPtr, |
| } |
|
|
| |
| |
| |
| 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: |
| |
| |
| |
| |
| |
| |
| if attrIsExprloc[attr] { |
| return ClassExprLoc |
| } |
| return ClassBlock |
|
|
| case formData1, formData2, formData4, formData8, formSdata, formUdata, formData16, formImplicitConst: |
| |
| |
| |
| |
| |
| 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: |
| |
| |
| |
| 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 |
| } |
| } |
|
|
| |
| type Entry struct { |
| Offset Offset |
| Tag Tag |
| Children bool |
| Field []Field |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| type Field struct { |
| Attr Attr |
| Val any |
| Class Class |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| type Class int |
|
|
| const ( |
| |
| ClassUnknown Class = iota |
|
|
| |
| |
| ClassAddress |
|
|
| |
| |
| ClassBlock |
|
|
| |
| |
| |
| ClassConstant |
|
|
| |
| |
| ClassExprLoc |
|
|
| |
| ClassFlag |
|
|
| |
| |
| ClassLinePtr |
|
|
| |
| |
| ClassLocListPtr |
|
|
| |
| |
| ClassMacPtr |
|
|
| |
| |
| ClassRangeListPtr |
|
|
| |
| |
| |
| |
| ClassReference |
|
|
| |
| |
| ClassReferenceSig |
|
|
| |
| |
| |
| |
| ClassString |
|
|
| |
| |
| |
| ClassReferenceAlt |
|
|
| |
| |
| |
| ClassStringAlt |
|
|
| |
| |
| ClassAddrPtr |
|
|
| |
| |
| ClassLocList |
|
|
| |
| |
| ClassRngList |
|
|
| |
| |
| |
| ClassRngListsPtr |
|
|
| |
| |
| ClassStrOffsetsPtr |
| ) |
|
|
| |
|
|
| func (i Class) GoString() string { |
| return "dwarf." + i.String() |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| func (e *Entry) Val(a Attr) any { |
| if f := e.AttrField(a); f != nil { |
| return f.Val |
| } |
| return nil |
| } |
|
|
| |
| |
| func (e *Entry) AttrField(a Attr) *Field { |
| for i, f := range e.Field { |
| if f.Attr == a { |
| return &e.Field[i] |
| } |
| } |
| return nil |
| } |
|
|
| |
| |
| type Offset uint32 |
|
|
| |
| |
| func (b *buf) entry(cu *Entry, u *unit) *Entry { |
| atab, ubase, vers := u.atable, u.base, u.vers |
| 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)), |
| } |
|
|
| 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)) |
|
|
| |
| 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 |
| } |
|
|
| addrBase := int64(u.addrBase()) |
| 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 |
| } |
|
|
| |
| 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())) |
|
|
| |
| 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 = b.int() |
| case formUdata: |
| val = int64(b.uint()) |
| case formImplicitConst: |
| val = a.field[i].val |
|
|
| |
| case formFlag: |
| val = b.uint8() == 1 |
| |
| case formFlagPresent: |
| |
| |
| val = true |
|
|
| |
| 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 |
|
|
| |
| case formString: |
| val = b.string() |
| case formStrp, formLineStrp: |
| var off uint64 |
| 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 |
| } |
|
|
| strBase := int64(u.strOffsetsBase()) |
| 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() |
| } |
|
|
| |
| |
| |
| 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()) |
| } |
|
|
| |
| |
| case formExprloc: |
| val = b.bytes(int(b.uint())) |
|
|
| |
| |
| case formRefSig8: |
| |
| val = b.uint64() |
| case formRefSup4: |
| val = b.uint32() |
| case formRefSup8: |
| val = b.uint64() |
|
|
| |
| case formLoclistx: |
| val = b.uint() |
|
|
| |
| case formRnglistx: |
| off := b.uint() |
|
|
| rnglistsBase := int64(u.rngListsBase()) |
| val = resolveRnglistx(uint64(rnglistsBase), off) |
| } |
|
|
| e.Field[i].Val = val |
| } |
| if b.err != nil { |
| return nil |
| } |
| return e |
| } |
|
|
| |
| |
| |
| |
| |
| type Reader struct { |
| b buf |
| d *Data |
| err error |
| unit int |
| lastUnit bool |
| lastChildren bool |
| lastSibling Offset |
| cu *Entry |
| } |
|
|
| |
| |
| func (d *Data) Reader() *Reader { |
| r := &Reader{d: d} |
| r.Seek(0) |
| return r |
| } |
|
|
| |
| |
| func (r *Reader) AddressSize() int { |
| return r.d.unit[r.unit].asize |
| } |
|
|
| |
| func (r *Reader) ByteOrder() binary.ByteOrder { |
| return r.b.order |
| } |
|
|
| |
| |
| 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.collectDwarf5BaseOffsets(u) |
| 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:]) |
| r.collectDwarf5BaseOffsets(u) |
| } |
|
|
| |
| func (r *Reader) maybeNextUnit() { |
| for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) { |
| r.nextUnit() |
| } |
| } |
|
|
| |
| 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 |
| r.collectDwarf5BaseOffsets(u) |
| } |
|
|
| func (r *Reader) collectDwarf5BaseOffsets(u *unit) { |
| if u.vers < 5 || u.unit5 != nil { |
| return |
| } |
| u.unit5 = new(unit5) |
| if err := r.d.collectDwarf5BaseOffsets(u); err != nil { |
| r.err = err |
| } |
| } |
|
|
| |
| |
| |
| |
| 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) |
| 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 |
| } |
|
|
| |
| |
| |
| func (r *Reader) SkipChildren() { |
| if r.err != nil || !r.lastChildren { |
| return |
| } |
|
|
| |
| |
| |
| |
| 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() |
| } |
| } |
| } |
|
|
| |
| |
| func (r *Reader) clone() typeReader { |
| return r.d.Reader() |
| } |
|
|
| |
| |
| func (r *Reader) offset() Offset { |
| return r.b.off |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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) |
| r.collectDwarf5BaseOffsets(u) |
| e, err := r.Next() |
| if err != nil { |
| return nil, err |
| } |
| if e == nil || e.Tag == 0 { |
| return nil, ErrUnknownPC |
| } |
| 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 |
| } |
|
|
| |
| |
| |
| 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 { |
| |
| 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 |
| } |
| } |
|
|
| |
| 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 |
| } |
|
|
| |
| |
| |
| |
| |
| 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) |
| 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) { |
| if ranges < 0 || ranges > int64(len(d.ranges)) { |
| return nil, fmt.Errorf("invalid range offset %d (max %d)", ranges, len(d.ranges)) |
| } |
| 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 |
| } |
|
|
| |
| |
| func (d *Data) dwarf5Ranges(u *unit, cu *Entry, base uint64, ranges int64, ret [][2]uint64) ([][2]uint64, error) { |
| if ranges < 0 || ranges > int64(len(d.rngLists)) { |
| return nil, fmt.Errorf("invalid rnglist offset %d (max %d)", ranges, len(d.ranges)) |
| } |
| 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}) |
| } |
| } |
| } |
|
|
| |
| 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 |
| } |
|
|