proc: do not assume abstract origins precede their uses (#2293)
The DWARF standard does not say that a DW_ATTR_abstract_origin can only reference entries that appear before it, this change fixes BinaryInfo to comply. See #2284 for an example of this happening.
This commit is contained in:
parent
3c86d68a99
commit
f5d5a681d0
@ -123,10 +123,11 @@ func (b *Builder) TagClose() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attr adds an attribute to the current DIE.
|
// Attr adds an attribute to the current DIE.
|
||||||
func (b *Builder) Attr(attr dwarf.Attr, val interface{}) {
|
func (b *Builder) Attr(attr dwarf.Attr, val interface{}) dwarf.Offset {
|
||||||
if len(b.tagStack) < 0 {
|
if len(b.tagStack) < 0 {
|
||||||
panic("Attr with no open tags")
|
panic("Attr with no open tags")
|
||||||
}
|
}
|
||||||
|
off := dwarf.Offset(b.info.Len())
|
||||||
tag := b.tagStack[len(b.tagStack)-1]
|
tag := b.tagStack[len(b.tagStack)-1]
|
||||||
if tag.children {
|
if tag.children {
|
||||||
panic("Can't add attributes after adding children")
|
panic("Can't add attributes after adding children")
|
||||||
@ -179,6 +180,16 @@ func (b *Builder) Attr(attr dwarf.Attr, val interface{}) {
|
|||||||
default:
|
default:
|
||||||
panic("unknown value type")
|
panic("unknown value type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return off
|
||||||
|
}
|
||||||
|
|
||||||
|
// PatchOffset writes the offset 'patch' at offset patchedOffset.
|
||||||
|
func (b *Builder) PatchOffset(patchedOffset, patch dwarf.Offset) {
|
||||||
|
infoBytes := b.info.Bytes()
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
binary.Write(buf, binary.LittleEndian, patch)
|
||||||
|
copy(infoBytes[patchedOffset:], buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func sameTagDescr(a, b tagDescr) bool {
|
func sameTagDescr(a, b tagDescr) bool {
|
||||||
|
@ -1787,18 +1787,15 @@ func (bi *BinaryInfo) addAbstractSubprogram(entry *dwarf.Entry, ctxt *loadDebugI
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fn := Function{
|
|
||||||
Name: name,
|
|
||||||
offset: entry.Offset,
|
|
||||||
cu: cu,
|
|
||||||
}
|
|
||||||
|
|
||||||
if entry.Children {
|
if entry.Children {
|
||||||
bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
|
bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
|
||||||
}
|
}
|
||||||
|
|
||||||
bi.Functions = append(bi.Functions, fn)
|
originIdx := ctxt.lookupAbstractOrigin(bi, entry.Offset)
|
||||||
ctxt.abstractOriginTable[entry.Offset] = len(bi.Functions) - 1
|
fn := &bi.Functions[originIdx]
|
||||||
|
fn.Name = name
|
||||||
|
fn.offset = entry.Offset
|
||||||
|
fn.cu = cu
|
||||||
}
|
}
|
||||||
|
|
||||||
// addConcreteInlinedSubprogram adds the concrete entry of a subprogram that was also inlined.
|
// addConcreteInlinedSubprogram adds the concrete entry of a subprogram that was also inlined.
|
||||||
@ -1812,15 +1809,7 @@ func (bi *BinaryInfo) addConcreteInlinedSubprogram(entry *dwarf.Entry, originOff
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
originIdx, ok := ctxt.abstractOriginTable[originOffset]
|
originIdx := ctxt.lookupAbstractOrigin(bi, originOffset)
|
||||||
if !ok {
|
|
||||||
bi.logger.Warnf("reading debug_info: could not find abstract origin of concrete inlined subprogram at %#x (origin offset %#x)", entry.Offset, originOffset)
|
|
||||||
if entry.Children {
|
|
||||||
reader.SkipChildren()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := &bi.Functions[originIdx]
|
fn := &bi.Functions[originIdx]
|
||||||
fn.offset = entry.Offset
|
fn.offset = entry.Offset
|
||||||
fn.Entry = lowpc
|
fn.Entry = lowpc
|
||||||
@ -1905,12 +1894,7 @@ func (bi *BinaryInfo) loadDebugInfoMapsInlinedCalls(ctxt *loadDebugInfoMapsConte
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
originIdx, ok := ctxt.abstractOriginTable[originOffset]
|
originIdx := ctxt.lookupAbstractOrigin(bi, originOffset)
|
||||||
if !ok {
|
|
||||||
bi.logger.Warnf("reading debug_info: could not find abstract origin (%#x) of inlined call at %#x", originOffset, entry.Offset)
|
|
||||||
reader.SkipChildren()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fn := &bi.Functions[originIdx]
|
fn := &bi.Functions[originIdx]
|
||||||
|
|
||||||
lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
|
lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
|
||||||
|
@ -353,3 +353,43 @@ func TestNestedCompileUnts(t *testing.T) {
|
|||||||
t.Errorf("expected 2 variables, got %d", n)
|
t.Errorf("expected 2 variables, got %d", n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAbstractOriginDefinedAfterUse(t *testing.T) {
|
||||||
|
// Tests that an abstract origin entry can appear after its uses.
|
||||||
|
dwb := dwarfbuilder.New()
|
||||||
|
dwb.AddCompileUnit("main", 0x0)
|
||||||
|
|
||||||
|
// Concrete implementation
|
||||||
|
dwb.TagOpen(dwarf.TagSubprogram, "")
|
||||||
|
originRef1 := dwb.Attr(dwarf.AttrAbstractOrigin, dwarf.Offset(0))
|
||||||
|
dwb.Attr(dwarf.AttrLowpc, dwarfbuilder.Address(0x40100))
|
||||||
|
dwb.Attr(dwarf.AttrHighpc, dwarfbuilder.Address(0x41000))
|
||||||
|
dwb.TagClose()
|
||||||
|
|
||||||
|
// Inlined call
|
||||||
|
dwb.AddSubprogram("callingFn", 0x41100, 0x42000)
|
||||||
|
dwb.TagOpen(dwarf.TagInlinedSubroutine, "")
|
||||||
|
originRef2 := dwb.Attr(dwarf.AttrAbstractOrigin, dwarf.Offset(0))
|
||||||
|
dwb.Attr(dwarf.AttrLowpc, dwarfbuilder.Address(0x41150))
|
||||||
|
dwb.Attr(dwarf.AttrHighpc, dwarfbuilder.Address(0x41155))
|
||||||
|
dwb.Attr(dwarf.AttrCallFile, uint8(1))
|
||||||
|
dwb.Attr(dwarf.AttrCallLine, uint8(1))
|
||||||
|
dwb.TagClose()
|
||||||
|
dwb.TagClose()
|
||||||
|
|
||||||
|
// Abstract origin
|
||||||
|
abstractOriginOff := dwb.TagOpen(dwarf.TagSubprogram, "inlinedFn")
|
||||||
|
dwb.Attr(dwarf.AttrInline, uint8(1))
|
||||||
|
dwb.TagClose()
|
||||||
|
|
||||||
|
dwb.TagClose()
|
||||||
|
|
||||||
|
dwb.PatchOffset(originRef1, abstractOriginOff)
|
||||||
|
dwb.PatchOffset(originRef2, abstractOriginOff)
|
||||||
|
|
||||||
|
bi, _ := fakeBinaryInfo(t, dwb)
|
||||||
|
fn := bi.PCToFunc(0x40100)
|
||||||
|
if fn == nil {
|
||||||
|
t.Fatalf("could not find concrete instance of inlined function")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -98,6 +98,16 @@ func newLoadDebugInfoMapsContext(bi *BinaryInfo, image *Image, offsetToVersion m
|
|||||||
return ctxt
|
return ctxt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctxt *loadDebugInfoMapsContext) lookupAbstractOrigin(bi *BinaryInfo, off dwarf.Offset) int {
|
||||||
|
r, ok := ctxt.abstractOriginTable[off]
|
||||||
|
if !ok {
|
||||||
|
bi.Functions = append(bi.Functions, Function{})
|
||||||
|
r = len(bi.Functions) - 1
|
||||||
|
ctxt.abstractOriginTable[off] = r
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// runtimeTypeToDIE returns the DIE corresponding to the runtime._type.
|
// runtimeTypeToDIE returns the DIE corresponding to the runtime._type.
|
||||||
// This is done in three different ways depending on the version of go.
|
// This is done in three different ways depending on the version of go.
|
||||||
// * Before go1.7 the type name is retrieved directly from the runtime._type
|
// * Before go1.7 the type name is retrieved directly from the runtime._type
|
||||||
|
Loading…
Reference in New Issue
Block a user