Commit d5cb7152 authored by Ian Lance Taylor's avatar Ian Lance Taylor Committed by Kirill Smelkov

debug/dwarf, debug/elf: support DWARF 5

Change-Id: I6e9d47865c198299d497911c58235cd40f775e34
Reviewed-on: https://go-review.googlesource.com/c/go/+/175138
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarThan McIntosh <thanm@google.com>
parent a724597f
...@@ -99,6 +99,18 @@ func (b *buf) uint16() uint16 { ...@@ -99,6 +99,18 @@ func (b *buf) uint16() uint16 {
return b.order.Uint16(a) return b.order.Uint16(a)
} }
func (b *buf) uint24() uint32 {
a := b.bytes(3)
if a == nil {
return 0
}
if b.dwarf.bigEndian {
return uint32(a[2]) | uint32(a[1])<<8 | uint32(a[0])<<16
} else {
return uint32(a[0]) | uint32(a[1])<<8 | uint32(a[2])<<16
}
}
func (b *buf) uint32() uint32 { func (b *buf) uint32() uint32 {
a := b.bytes(4) a := b.bytes(4)
if a == nil { if a == nil {
......
...@@ -26,6 +26,7 @@ type afield struct { ...@@ -26,6 +26,7 @@ type afield struct {
attr Attr attr Attr
fmt format fmt format
class Class class Class
val int64 // for formImplicitConst
} }
// a map from entry format ids to their descriptions // a map from entry format ids to their descriptions
...@@ -67,6 +68,9 @@ func (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) { ...@@ -67,6 +68,9 @@ func (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) {
if tag == 0 && fmt == 0 { if tag == 0 && fmt == 0 {
break break
} }
if format(fmt) == formImplicitConst {
b1.int()
}
n++ n++
} }
if b1.err != nil { if b1.err != nil {
...@@ -82,6 +86,9 @@ func (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) { ...@@ -82,6 +86,9 @@ func (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) {
a.field[i].attr = Attr(b.uint()) a.field[i].attr = Attr(b.uint())
a.field[i].fmt = format(b.uint()) a.field[i].fmt = format(b.uint())
a.field[i].class = formToClass(a.field[i].fmt, a.field[i].attr, vers, &b) 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()
b.uint() b.uint()
...@@ -137,6 +144,11 @@ var attrPtrClass = map[Attr]Class{ ...@@ -137,6 +144,11 @@ var attrPtrClass = map[Attr]Class{
AttrUseLocation: ClassLocListPtr, AttrUseLocation: ClassLocListPtr,
AttrVtableElemLoc: ClassLocListPtr, AttrVtableElemLoc: ClassLocListPtr,
AttrRanges: ClassRangeListPtr, 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 // formToClass returns the DWARF 4 Class for the given form. If the
...@@ -148,7 +160,7 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class { ...@@ -148,7 +160,7 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class {
b.error("cannot determine class of unknown attribute form") b.error("cannot determine class of unknown attribute form")
return 0 return 0
case formAddr: case formAddr, formAddrx, formAddrx1, formAddrx2, formAddrx3, formAddrx4:
return ClassAddress return ClassAddress
case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock: case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock:
...@@ -163,7 +175,7 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class { ...@@ -163,7 +175,7 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class {
} }
return ClassBlock return ClassBlock
case formData1, formData2, formData4, formData8, formSdata, formUdata: case formData1, formData2, formData4, formData8, formSdata, formUdata, formData16, formImplicitConst:
// In DWARF 2 and 3, ClassPtr was encoded as a // In DWARF 2 and 3, ClassPtr was encoded as a
// constant. Unlike ClassExprLoc/ClassBlock, some // constant. Unlike ClassExprLoc/ClassBlock, some
// DWARF 4 attributes need to distinguish Class*Ptr // DWARF 4 attributes need to distinguish Class*Ptr
...@@ -177,13 +189,13 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class { ...@@ -177,13 +189,13 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class {
case formFlag, formFlagPresent: case formFlag, formFlagPresent:
return ClassFlag return ClassFlag
case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata: case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata, formRefSup4, formRefSup8:
return ClassReference return ClassReference
case formRefSig8: case formRefSig8:
return ClassReferenceSig return ClassReferenceSig
case formString, formStrp: case formString, formStrp, formStrx, formStrpSup, formLineStrp, formStrx1, formStrx2, formStrx3, formStrx4:
return ClassString return ClassString
case formSecOffset: case formSecOffset:
...@@ -203,6 +215,12 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class { ...@@ -203,6 +215,12 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class {
case formGnuStrpAlt: case formGnuStrpAlt:
return ClassStringAlt return ClassStringAlt
case formLoclistx:
return ClassLocList
case formRnglistx:
return ClassRngList
} }
} }
...@@ -324,6 +342,27 @@ const ( ...@@ -324,6 +342,27 @@ const (
// offset into the DWARF string section of an alternate object // offset into the DWARF string section of an alternate object
// file. // file.
ClassStringAlt 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 an int64 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 //go:generate stringer -type=Class
...@@ -363,7 +402,7 @@ type Offset uint32 ...@@ -363,7 +402,7 @@ type Offset uint32
// Entry reads a single entry from buf, decoding // Entry reads a single entry from buf, decoding
// according to the given abbreviation table. // according to the given abbreviation table.
func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { func (b *buf) entry(cu *Entry, atab abbrevTable, ubase Offset) *Entry {
off := b.off off := b.off
id := uint32(b.uint()) id := uint32(b.uint())
if id == 0 { if id == 0 {
...@@ -395,6 +434,54 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { ...@@ -395,6 +434,54 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// address // address
case formAddr: case formAddr:
val = b.addr() 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 len(b.dwarf.addr) == 0 {
b.error("DW_FORM_addrx with no .debug_addr section")
}
if b.err != nil {
return nil
}
addrsize := b.format.addrsize()
if addrsize == 0 {
b.error("unknown address size for DW_FORM_addrx")
}
off *= uint64(addrsize)
// 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.
if cu != nil {
cuOff, ok := cu.Val(AttrAddrBase).(int64)
if ok {
off += uint64(cuOff)
}
}
if uint64(int(off)) != off {
b.error("DW_FORM_addrx offset out of range")
}
b1 := makeBuf(b.dwarf, b.format, "addr", 0, b.dwarf.addr)
b1.skip(int(off))
val = b1.addr()
if b1.err != nil {
b.err = b1.err
return nil
}
// block // block
case formDwarfBlock1: case formDwarfBlock1:
...@@ -415,10 +502,14 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { ...@@ -415,10 +502,14 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
val = int64(b.uint32()) val = int64(b.uint32())
case formData8: case formData8:
val = int64(b.uint64()) val = int64(b.uint64())
case formData16:
val = b.bytes(16)
case formSdata: case formSdata:
val = int64(b.int()) val = int64(b.int())
case formUdata: case formUdata:
val = int64(b.uint()) val = int64(b.uint())
case formImplicitConst:
val = a.field[i].val
// flag // flag
case formFlag: case formFlag:
...@@ -460,29 +551,112 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { ...@@ -460,29 +551,112 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// string // string
case formString: case formString:
val = b.string() val = b.string()
case formStrp: case formStrp, formLineStrp:
var off uint64 // offset into .debug_str var off uint64 // offset into .debug_str
is64, known := b.format.dwarf64() is64, known := b.format.dwarf64()
if !known { if !known {
b.error("unknown size for DW_FORM_strp") b.error("unknown size for DW_FORM_strp/line_strp")
} else if is64 { } else if is64 {
off = b.uint64() off = b.uint64()
} else { } else {
off = uint64(b.uint32()) off = uint64(b.uint32())
} }
if uint64(int(off)) != off { if uint64(int(off)) != off {
b.error("DW_FORM_strp offset out of range") b.error("DW_FORM_strp/line_strp offset out of range")
} }
if b.err != nil { if b.err != nil {
return nil return nil
} }
b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str) 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")
}
b1 = makeBuf(b.dwarf, b.format, "line_str", 0, b.dwarf.lineStr)
}
b1.skip(int(off)) b1.skip(int(off))
val = b1.string() val = b1.string()
if b1.err != nil { if b1.err != nil {
b.err = b1.err b.err = b1.err
return nil 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.
if cu != nil {
cuOff, ok := cu.Val(AttrStrOffsetsBase).(int64)
if ok {
off += uint64(cuOff)
}
}
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))
if is64 {
off = b1.uint64()
} else {
off = uint64(b1.uint32())
}
if b1.err != nil {
b.err = b1.err
return nil
}
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 nil
}
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 // lineptr, loclistptr, macptr, rangelistptr
// New in DWARF 4, but clang can generate them with -gdwarf-2. // New in DWARF 4, but clang can generate them with -gdwarf-2.
...@@ -507,6 +681,18 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { ...@@ -507,6 +681,18 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
case formRefSig8: case formRefSig8:
// 64-bit type signature. // 64-bit type signature.
val = b.uint64() val = b.uint64()
case formRefSup4:
val = b.uint32()
case formRefSup8:
val = b.uint64()
// loclist
case formLoclistx:
val = b.uint()
// rnglist
case formRnglistx:
val = b.uint()
} }
e.Field[i].Val = val e.Field[i].Val = val
} }
...@@ -528,6 +714,7 @@ type Reader struct { ...@@ -528,6 +714,7 @@ type Reader struct {
unit int unit int
lastChildren bool // .Children of last entry returned by Next lastChildren bool // .Children of last entry returned by Next
lastSibling Offset // .Val(AttrSibling) 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. // Reader returns a new Reader for Data.
...@@ -557,6 +744,7 @@ func (r *Reader) Seek(off Offset) { ...@@ -557,6 +744,7 @@ func (r *Reader) Seek(off Offset) {
u := &d.unit[0] u := &d.unit[0]
r.unit = 0 r.unit = 0
r.b = makeBuf(r.d, u, "info", u.off, u.data) r.b = makeBuf(r.d, u, "info", u.off, u.data)
r.cu = nil
return return
} }
...@@ -565,6 +753,9 @@ func (r *Reader) Seek(off Offset) { ...@@ -565,6 +753,9 @@ func (r *Reader) Seek(off Offset) {
r.err = errors.New("offset out of range") r.err = errors.New("offset out of range")
return return
} }
if i != r.unit {
r.cu = nil
}
u := &d.unit[i] u := &d.unit[i]
r.unit = i r.unit = i
r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:]) r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
...@@ -576,6 +767,7 @@ func (r *Reader) maybeNextUnit() { ...@@ -576,6 +767,7 @@ func (r *Reader) maybeNextUnit() {
r.unit++ r.unit++
u := &r.d.unit[r.unit] u := &r.d.unit[r.unit]
r.b = makeBuf(r.d, u, "info", u.off, u.data) r.b = makeBuf(r.d, u, "info", u.off, u.data)
r.cu = nil
} }
} }
...@@ -592,7 +784,7 @@ func (r *Reader) Next() (*Entry, error) { ...@@ -592,7 +784,7 @@ func (r *Reader) Next() (*Entry, error) {
return nil, nil return nil, nil
} }
u := &r.d.unit[r.unit] u := &r.d.unit[r.unit]
e := r.b.entry(u.atable, u.base) e := r.b.entry(r.cu, u.atable, u.base)
if r.b.err != nil { if r.b.err != nil {
r.err = r.b.err r.err = r.b.err
return nil, r.err return nil, r.err
...@@ -602,6 +794,9 @@ func (r *Reader) Next() (*Entry, error) { ...@@ -602,6 +794,9 @@ func (r *Reader) Next() (*Entry, error) {
if r.lastChildren { if r.lastChildren {
r.lastSibling, _ = e.Val(AttrSibling).(Offset) r.lastSibling, _ = e.Val(AttrSibling).(Offset)
} }
if e.Tag == TagCompileUnit || e.Tag == TagPartialUnit {
r.cu = e
}
} else { } else {
r.lastChildren = false r.lastChildren = false
} }
...@@ -734,7 +929,7 @@ func (d *Data) Ranges(e *Entry) ([][2]uint64, error) { ...@@ -734,7 +929,7 @@ func (d *Data) Ranges(e *Entry) ([][2]uint64, error) {
} }
u := &d.unit[i] u := &d.unit[i]
b := makeBuf(d, u, "info", u.off, u.data) b := makeBuf(d, u, "info", u.off, u.data)
cu = b.entry(u.atable, u.base) cu = b.entry(nil, u.atable, u.base)
if b.err != nil { if b.err != nil {
return nil, b.err return nil, b.err
} }
......
...@@ -23,8 +23,13 @@ type LineReader struct { ...@@ -23,8 +23,13 @@ type LineReader struct {
// Original .debug_line section data. Used by Seek. // Original .debug_line section data. Used by Seek.
section []byte section []byte
str []byte // .debug_str
lineStr []byte // .debug_line_str
// Header information // Header information
version uint16 version uint16
addrsize int
segmentSelectorSize int
minInstructionLength int minInstructionLength int
maxOpsPerInstruction int maxOpsPerInstruction int
defaultIsStmt bool defaultIsStmt bool
...@@ -158,10 +163,15 @@ func (d *Data) LineReader(cu *Entry) (*LineReader, error) { ...@@ -158,10 +163,15 @@ func (d *Data) LineReader(cu *Entry) (*LineReader, error) {
u := &d.unit[d.offsetToUnit(cu.Offset)] u := &d.unit[d.offsetToUnit(cu.Offset)]
buf := makeBuf(d, u, "line", Offset(off), d.line[off:]) buf := makeBuf(d, u, "line", Offset(off), d.line[off:])
// The compilation directory is implicitly directories[0]. // The compilation directory is implicitly directories[0].
r := LineReader{buf: buf, section: d.line, directories: []string{compDir}} r := LineReader{
buf: buf,
section: d.line,
str: d.str,
lineStr: d.lineStr,
}
// Read the header. // Read the header.
if err := r.readHeader(); err != nil { if err := r.readHeader(compDir); err != nil {
return nil, err return nil, err
} }
...@@ -173,7 +183,7 @@ func (d *Data) LineReader(cu *Entry) (*LineReader, error) { ...@@ -173,7 +183,7 @@ func (d *Data) LineReader(cu *Entry) (*LineReader, error) {
// readHeader reads the line number program header from r.buf and sets // readHeader reads the line number program header from r.buf and sets
// all of the header fields in r. // all of the header fields in r.
func (r *LineReader) readHeader() error { func (r *LineReader) readHeader(compDir string) error {
buf := &r.buf buf := &r.buf
// Read basic header fields [DWARF2 6.2.4]. // Read basic header fields [DWARF2 6.2.4].
...@@ -184,7 +194,7 @@ func (r *LineReader) readHeader() error { ...@@ -184,7 +194,7 @@ func (r *LineReader) readHeader() error {
return DecodeError{"line", hdrOffset, fmt.Sprintf("line table end %d exceeds section size %d", r.endOffset, buf.off+Offset(len(buf.data)))} return DecodeError{"line", hdrOffset, fmt.Sprintf("line table end %d exceeds section size %d", r.endOffset, buf.off+Offset(len(buf.data)))}
} }
r.version = buf.uint16() r.version = buf.uint16()
if buf.err == nil && (r.version < 2 || r.version > 4) { if buf.err == nil && (r.version < 2 || r.version > 5) {
// DWARF goes to all this effort to make new opcodes // DWARF goes to all this effort to make new opcodes
// backward-compatible, and then adds fields right in // backward-compatible, and then adds fields right in
// the middle of the header in new versions, so we're // the middle of the header in new versions, so we're
...@@ -192,6 +202,13 @@ func (r *LineReader) readHeader() error { ...@@ -192,6 +202,13 @@ func (r *LineReader) readHeader() error {
// versions. // versions.
return DecodeError{"line", hdrOffset, fmt.Sprintf("unknown line table version %d", r.version)} return DecodeError{"line", hdrOffset, fmt.Sprintf("unknown line table version %d", r.version)}
} }
if r.version >= 5 {
r.addrsize = int(buf.uint8())
r.segmentSelectorSize = int(buf.uint8())
} else {
r.addrsize = buf.format.addrsize()
r.segmentSelectorSize = 0
}
var headerLength Offset var headerLength Offset
if dwarf64 { if dwarf64 {
headerLength = Offset(buf.uint64()) headerLength = Offset(buf.uint64())
...@@ -238,39 +255,170 @@ func (r *LineReader) readHeader() error { ...@@ -238,39 +255,170 @@ func (r *LineReader) readHeader() error {
} }
} }
// Read include directories table. The caller already set if r.version < 5 {
// directories[0] to the compilation directory. // Read include directories table.
for { r.directories = []string{compDir}
directory := buf.string() for {
if buf.err != nil { directory := buf.string()
return buf.err if buf.err != nil {
return buf.err
}
if len(directory) == 0 {
break
}
if !pathIsAbs(directory) {
// Relative paths are implicitly relative to
// the compilation directory.
directory = pathJoin(compDir, directory)
}
r.directories = append(r.directories, directory)
} }
if len(directory) == 0 {
break // Read file name list. File numbering starts with 1,
// so leave the first entry nil.
r.fileEntries = make([]*LineFile, 1)
for {
if done, err := r.readFileEntry(); err != nil {
return err
} else if done {
break
}
} }
if !pathIsAbs(directory) { } else {
// Relative paths are implicitly relative to dirFormat := r.readLNCTFormat()
// the compilation directory. c := buf.uint()
directory = pathJoin(r.directories[0], directory) r.directories = make([]string, c)
for i := range r.directories {
dir, _, _, err := r.readLNCT(dirFormat, dwarf64)
if err != nil {
return err
}
r.directories[i] = dir
} }
r.directories = append(r.directories, directory) fileFormat := r.readLNCTFormat()
} c = buf.uint()
r.fileEntries = make([]*LineFile, c)
// Read file name list. File numbering starts with 1, so leave for i := range r.fileEntries {
// the first entry nil. name, mtime, size, err := r.readLNCT(fileFormat, dwarf64)
r.fileEntries = make([]*LineFile, 1) if err != nil {
for { return err
if done, err := r.readFileEntry(); err != nil { }
return err r.fileEntries[i] = &LineFile{name, mtime, int(size)}
} else if done {
break
} }
} }
r.initialFileEntries = len(r.fileEntries) r.initialFileEntries = len(r.fileEntries)
return buf.err return buf.err
} }
// lnctForm is a pair of an LNCT code and a form. This represents an
// entry in the directory name or file name description in the DWARF 5
// line number program header.
type lnctForm struct {
lnct int
form format
}
// readLNCTFormat reads an LNCT format description.
func (r *LineReader) readLNCTFormat() []lnctForm {
c := r.buf.uint8()
ret := make([]lnctForm, c)
for i := range ret {
ret[i].lnct = int(r.buf.uint())
ret[i].form = format(r.buf.uint())
}
return ret
}
// readLNCT reads a sequence of LNCT entries and returns path information.
func (r *LineReader) readLNCT(s []lnctForm, dwarf64 bool) (path string, mtime uint64, size uint64, err error) {
var dir string
for _, lf := range s {
var str string
var val uint64
switch lf.form {
case formString:
str = r.buf.string()
case formStrp, formLineStrp:
var off uint64
if dwarf64 {
off = r.buf.uint64()
} else {
off = uint64(r.buf.uint32())
}
if uint64(int(off)) != off {
return "", 0, 0, DecodeError{"line", r.buf.off, "strp/line_strp offset out of range"}
}
var b1 buf
if lf.form == formStrp {
b1 = makeBuf(r.buf.dwarf, r.buf.format, "str", 0, r.str)
} else {
b1 = makeBuf(r.buf.dwarf, r.buf.format, "line_str", 0, r.lineStr)
}
b1.skip(int(off))
str = b1.string()
if b1.err != nil {
return "", 0, 0, DecodeError{"line", r.buf.off, b1.err.Error()}
}
case formStrpSup:
// Supplemental sections not yet supported.
if dwarf64 {
r.buf.uint64()
} else {
r.buf.uint32()
}
case formStrx:
// .debug_line.dwo sections not yet supported.
r.buf.uint()
case formStrx1:
r.buf.uint8()
case formStrx2:
r.buf.uint16()
case formStrx3:
r.buf.uint24()
case formStrx4:
r.buf.uint32()
case formData1:
val = uint64(r.buf.uint8())
case formData2:
val = uint64(r.buf.uint16())
case formData4:
val = uint64(r.buf.uint32())
case formData8:
val = r.buf.uint64()
case formData16:
r.buf.bytes(16)
case formDwarfBlock:
r.buf.bytes(int(r.buf.uint()))
case formUdata:
val = r.buf.uint()
}
switch lf.lnct {
case lnctPath:
path = str
case lnctDirectoryIndex:
if val >= uint64(len(r.directories)) {
return "", 0, 0, DecodeError{"line", r.buf.off, "directory index out of range"}
}
dir = r.directories[val]
case lnctTimestamp:
mtime = val
case lnctSize:
size = val
case lnctMD5:
// Ignored.
}
}
if dir != "" && path != "" {
path = pathJoin(dir, path)
}
return path, mtime, size, nil
}
// readFileEntry reads a file entry from either the header or a // readFileEntry reads a file entry from either the header or a
// DW_LNE_define_file extended opcode and adds it to r.fileEntries. A // DW_LNE_define_file extended opcode and adds it to r.fileEntries. A
// true return value indicates that there are no more entries to read. // true return value indicates that there are no more entries to read.
...@@ -381,7 +529,18 @@ func (r *LineReader) step(entry *LineEntry) bool { ...@@ -381,7 +529,18 @@ func (r *LineReader) step(entry *LineEntry) bool {
r.resetState() r.resetState()
case lneSetAddress: case lneSetAddress:
r.state.Address = r.buf.addr() switch r.addrsize {
case 1:
r.state.Address = uint64(r.buf.uint8())
case 2:
r.state.Address = uint64(r.buf.uint16())
case 4:
r.state.Address = uint64(r.buf.uint32())
case 8:
r.state.Address = r.buf.uint64()
default:
r.buf.error("unknown address size")
}
case lneDefineFile: case lneDefineFile:
if done, err := r.readFileEntry(); err != nil { if done, err := r.readFileEntry(); err != nil {
......
...@@ -22,8 +22,14 @@ type Data struct { ...@@ -22,8 +22,14 @@ type Data struct {
ranges []byte ranges []byte
str []byte str []byte
// New sections added in DWARF 5.
addr []byte
lineStr []byte
strOffsets []byte
// parsed data // parsed data
abbrevCache map[uint64]abbrevTable abbrevCache map[uint64]abbrevTable
bigEndian bool
order binary.ByteOrder order binary.ByteOrder
typeCache map[Offset]Type typeCache map[Offset]Type
typeSigs map[uint64]*typeUnit typeSigs map[uint64]*typeUnit
...@@ -72,8 +78,10 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat ...@@ -72,8 +78,10 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
case x == 0 && y == 0: case x == 0 && y == 0:
return nil, DecodeError{"info", 4, "unsupported version 0"} return nil, DecodeError{"info", 4, "unsupported version 0"}
case x == 0: case x == 0:
d.bigEndian = true
d.order = binary.BigEndian d.order = binary.BigEndian
case y == 0: case y == 0:
d.bigEndian = false
d.order = binary.LittleEndian d.order = binary.LittleEndian
default: default:
return nil, DecodeError{"info", 4, "cannot determine byte order"} return nil, DecodeError{"info", 4, "cannot determine byte order"}
...@@ -94,3 +102,20 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat ...@@ -94,3 +102,20 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
func (d *Data) AddTypes(name string, types []byte) error { func (d *Data) AddTypes(name string, types []byte) error {
return d.parseTypes(name, types) return d.parseTypes(name, types)
} }
// AddSection adds another DWARF section by name. The name should be a
// DWARF section name such as ".debug_addr", ".debug_str_offsets", and
// so forth. This approach is used for new DWARF sections added in
// DWARF 5 and later.
func (d *Data) AddSection(name string, contents []byte) error {
switch name {
case ".debug_addr":
d.addr = contents
case ".debug_line_str":
d.lineStr = contents
case ".debug_str_offsets":
d.strOffsets = contents
}
// Just ignore names that we don't yet support.
return nil
}
...@@ -137,7 +137,7 @@ func (tur *typeUnitReader) Next() (*Entry, error) { ...@@ -137,7 +137,7 @@ func (tur *typeUnitReader) Next() (*Entry, error) {
if len(tur.tu.data) == 0 { if len(tur.tu.data) == 0 {
return nil, nil return nil, nil
} }
e := tur.b.entry(tur.tu.atable, tur.tu.base) e := tur.b.entry(nil, tur.tu.atable, tur.tu.base)
if tur.b.err != nil { if tur.b.err != nil {
tur.err = tur.b.err tur.err = tur.b.err
return nil, tur.err return nil, tur.err
......
...@@ -19,7 +19,8 @@ type unit struct { ...@@ -19,7 +19,8 @@ type unit struct {
atable abbrevTable atable abbrevTable
asize int asize int
vers int vers int
is64 bool // True for 64-bit DWARF format utype uint8 // DWARF 5 unit type
is64 bool // True for 64-bit DWARF format
} }
// Implement the dataFormat interface. // Implement the dataFormat interface.
...@@ -63,11 +64,15 @@ func (d *Data) parseUnits() ([]unit, error) { ...@@ -63,11 +64,15 @@ func (d *Data) parseUnits() ([]unit, error) {
n, u.is64 = b.unitLength() n, u.is64 = b.unitLength()
dataOff := b.off dataOff := b.off
vers := b.uint16() vers := b.uint16()
if vers != 2 && vers != 3 && vers != 4 { if vers < 2 || vers > 5 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break break
} }
u.vers = int(vers) u.vers = int(vers)
if vers >= 5 {
u.utype = b.uint8()
u.asize = int(b.uint8())
}
var abbrevOff uint64 var abbrevOff uint64
if u.is64 { if u.is64 {
abbrevOff = b.uint64() abbrevOff = b.uint64()
...@@ -82,7 +87,22 @@ func (d *Data) parseUnits() ([]unit, error) { ...@@ -82,7 +87,22 @@ func (d *Data) parseUnits() ([]unit, error) {
break break
} }
u.atable = atable u.atable = atable
u.asize = int(b.uint8()) if vers < 5 {
u.asize = int(b.uint8())
}
switch u.utype {
case utSkeleton, utSplitCompile:
b.uint64() // unit ID
case utType, utSplitType:
b.uint64() // type signature
if u.is64 { // type offset
b.uint64()
} else {
b.uint32()
}
}
u.off = b.off u.off = b.off
u.data = b.bytes(int(n - (b.off - dataOff))) u.data = b.bytes(int(n - (b.off - dataOff)))
} }
......
...@@ -1166,9 +1166,8 @@ func (f *File) DWARF() (*dwarf.Data, error) { ...@@ -1166,9 +1166,8 @@ func (f *File) DWARF() (*dwarf.Data, error) {
return b, nil return b, nil
} }
// There are many other DWARF sections, but these // There are many DWARf sections, but these are the ones
// are the ones the debug/dwarf package uses. // the debug/dwarf package started with.
// Don't bother loading others.
var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
for i, s := range f.Sections { for i, s := range f.Sections {
suffix := dwarfSuffix(s) suffix := dwarfSuffix(s)
...@@ -1190,10 +1189,14 @@ func (f *File) DWARF() (*dwarf.Data, error) { ...@@ -1190,10 +1189,14 @@ func (f *File) DWARF() (*dwarf.Data, error) {
return nil, err return nil, err
} }
// Look for DWARF4 .debug_types sections. // Look for DWARF4 .debug_types sections and DWARF5 sections.
for i, s := range f.Sections { for i, s := range f.Sections {
suffix := dwarfSuffix(s) suffix := dwarfSuffix(s)
if suffix != "types" { if suffix == "" {
continue
}
if _, ok := dat[suffix]; ok {
// Already handled.
continue continue
} }
...@@ -1202,9 +1205,14 @@ func (f *File) DWARF() (*dwarf.Data, error) { ...@@ -1202,9 +1205,14 @@ func (f *File) DWARF() (*dwarf.Data, error) {
return nil, err return nil, err
} }
err = d.AddTypes(fmt.Sprintf("types-%d", i), b) if suffix == "types" {
if err != nil { if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil {
return nil, err return nil, err
}
} else {
if err := d.AddSection(".debug_"+suffix, b); err != nil {
return nil, err
}
} }
} }
......
  • This commit is used to patch go on slapos repository. Writing this comment will make sure the commit is preserved by gitlab.

  • mentioned in commit 28fbdd01

    Toggle commit list
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment