提交 38307f92 编写于 作者: S Sergio Lopez 提交者: Derek Parker

proc: add support for dwz compressed DWARF

'dwz' is a tool that reduces the size of DWARF sections by
deduplicating symbols. The deduplicated symbols are moved from their
original 'compile unit' to a 'partial unit', which is then referenced
from its original location with an 'imported unit' tag.

In the case of Go binaries, all symbols are located in a single
'compile unit', and the name of each symbol contains a reference to its
package, so 'dwz' is not able to deduplicate them. But still, some C
symbols included in the binary are deduplicated, which also alters the
structure of the DWARF sections, making delve unable to parse them
(crashing in the attempt).

While it would've been possible to simply ignore the C symbols, or
blindly loading all then into BinaryInfo members (packageVars,
Functions...), for correctness sake this change tries to do the right
thing, staging symbols into temporary partialUnit objects, moving them
to BinaryInfo when they are actually requested  by a 'imported unit'
tag.
上级 3c794eb3
......@@ -78,6 +78,20 @@ type compileUnit struct {
optimized bool // this compile unit is optimized
}
type partialUnitConstant struct {
name string
typ dwarf.Offset
value int64
}
type partialUnit struct {
entry *dwarf.Entry
types map[string]dwarf.Offset
variables []packageVar
constants []partialUnitConstant
functions []Function
}
// Function describes a function in the target program.
type Function struct {
Name string
......
......@@ -188,12 +188,18 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou
bi.consts = make(map[dwarf.Offset]*constantType)
reader := bi.DwarfReader()
var cu *compileUnit = nil
var pu *partialUnit = nil
var partialUnits = make(map[dwarf.Offset]*partialUnit)
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
break
}
switch entry.Tag {
case dwarf.TagCompileUnit:
if pu != nil {
partialUnits[pu.entry.Offset] = pu
pu = nil
}
cu = &compileUnit{}
cu.entry = entry
if lang, _ := entry.Val(dwarf.AttrLanguage).(int64); lang == dwarfGoLanguage {
......@@ -218,29 +224,101 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou
}
bi.compileUnits = append(bi.compileUnits, cu)
case dwarf.TagPartialUnit:
if pu != nil {
partialUnits[pu.entry.Offset] = pu
pu = nil
}
pu = &partialUnit{}
pu.entry = entry
pu.types = make(map[string]dwarf.Offset)
case dwarf.TagImportedUnit:
if unit, exists := partialUnits[entry.Val(dwarf.AttrImport).(dwarf.Offset)]; exists {
for name, offset := range unit.types {
if pu != nil {
pu.types[name] = offset
} else {
if !cu.isgo {
name = "C." + name
}
bi.types[name] = offset
}
}
for _, pVar := range unit.variables {
if pu != nil {
pu.variables = append(pu.variables, pVar)
} else {
if !cu.isgo {
pVar.name = "C." + pVar.name
}
bi.packageVars = append(bi.packageVars, pVar)
}
}
for _, pCt := range unit.constants {
if pu != nil {
pu.constants = append(pu.constants, pCt)
} else {
if !cu.isgo {
pCt.name = "C." + pCt.name
}
ct := bi.consts[pCt.typ]
if ct == nil {
ct = &constantType{}
bi.consts[pCt.typ] = ct
}
ct.values = append(ct.values, constantValue{name: pCt.name, fullName: pCt.name, value: pCt.value})
}
}
for _, pFunc := range unit.functions {
if pu != nil {
pu.functions = append(pu.functions, pFunc)
} else {
if !cu.isgo {
pFunc.Name = "C." + pFunc.Name
}
pFunc.cu = cu
bi.Functions = append(bi.Functions, pFunc)
}
}
}
case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
if name, ok := entry.Val(dwarf.AttrName).(string); ok {
if !cu.isgo {
name = "C." + name
}
if _, exists := bi.types[name]; !exists {
bi.types[name] = entry.Offset
if pu != nil {
if _, exists := pu.types[name]; !exists {
pu.types[name] = entry.Offset
}
} else {
if !cu.isgo {
name = "C." + name
}
if _, exists := bi.types[name]; !exists {
bi.types[name] = entry.Offset
}
}
}
reader.SkipChildren()
case dwarf.TagVariable:
if n, ok := entry.Val(dwarf.AttrName).(string); ok {
if !cu.isgo {
n = "C." + n
}
var addr uint64
if loc, ok := entry.Val(dwarf.AttrLocation).([]byte); ok {
if len(loc) == bi.Arch.PtrSize()+1 && op.Opcode(loc[0]) == op.DW_OP_addr {
addr = binary.LittleEndian.Uint64(loc[1:])
}
}
bi.packageVars = append(bi.packageVars, packageVar{n, entry.Offset, addr})
if pu != nil {
pu.variables = append(pu.variables, packageVar{n, entry.Offset, addr})
} else {
if !cu.isgo {
n = "C." + n
}
bi.packageVars = append(bi.packageVars, packageVar{n, entry.Offset, addr})
}
}
case dwarf.TagConstant:
......@@ -248,15 +326,19 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou
typ, okType := entry.Val(dwarf.AttrType).(dwarf.Offset)
val, okVal := entry.Val(dwarf.AttrConstValue).(int64)
if okName && okType && okVal {
if !cu.isgo {
name = "C." + name
}
ct := bi.consts[typ]
if ct == nil {
ct = &constantType{}
bi.consts[typ] = ct
if pu != nil {
pu.constants = append(pu.constants, partialUnitConstant{name: name, typ: typ, value: val})
} else {
if !cu.isgo {
name = "C." + name
}
ct := bi.consts[typ]
if ct == nil {
ct = &constantType{}
bi.consts[typ] = ct
}
ct.values = append(ct.values, constantValue{name: name, fullName: name, value: val})
}
ct.values = append(ct.values, constantValue{name: name, fullName: name, value: val})
}
case dwarf.TagSubprogram:
......@@ -269,15 +351,24 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou
}
name, ok2 := entry.Val(dwarf.AttrName).(string)
if ok1 && ok2 {
if !cu.isgo {
name = "C." + name
if pu != nil {
pu.functions = append(pu.functions, Function{
Name: name,
Entry: lowpc, End: highpc,
offset: entry.Offset,
cu: &compileUnit{},
})
} else {
if !cu.isgo {
name = "C." + name
}
bi.Functions = append(bi.Functions, Function{
Name: name,
Entry: lowpc, End: highpc,
offset: entry.Offset,
cu: cu,
})
}
bi.Functions = append(bi.Functions, Function{
Name: name,
Entry: lowpc, End: highpc,
offset: entry.Offset,
cu: cu,
})
}
reader.SkipChildren()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册