| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | 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 |
| | } |
| |
|