Skip to content

Commit

Permalink
fix: dwarf edge case
Browse files Browse the repository at this point in the history
Signed-off-by: Zxilly <[email protected]>
  • Loading branch information
Zxilly committed Jun 19, 2024
1 parent 07ec454 commit a33a752
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 57 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/built-tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Tests
name: Tests and build

on:
push:
Expand Down
9 changes: 9 additions & 0 deletions cmd/gsa/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
package main

import (
"log/slog"

"github.com/alecthomas/kong"

gsv "github.com/Zxilly/go-size-analyzer"
"github.com/Zxilly/go-size-analyzer/internal/utils"
"github.com/Zxilly/go-size-analyzer/internal/webui"
)

Expand Down Expand Up @@ -90,4 +93,10 @@ func init() {
return nil
}),
)

if Options.Verbose {
utils.InitLogger(slog.LevelDebug)
} else {
utils.InitLogger(slog.LevelWarn)
}
}
6 changes: 0 additions & 6 deletions cmd/gsa/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ import (
)

func entry() error {
if Options.Verbose {
utils.InitLogger(slog.LevelDebug)
} else {
utils.InitLogger(slog.LevelWarn)
}

utils.ApplyMemoryLimit()

reader, err := mmap.Open(Options.Binary)
Expand Down
21 changes: 11 additions & 10 deletions internal/dwarf/dwarf.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"debug/dwarf"
"fmt"
"log/slog"
"strconv"
"strings"
)

Expand Down Expand Up @@ -86,17 +87,13 @@ func EntryShouldIgnore(entry *dwarf.Entry) bool {
declaration := entry.Val(dwarf.AttrDeclaration)
if declaration != nil {
val, ok := declaration.(bool)
if ok && val {
return true
}
return !ok || val
}

inline := entry.Val(dwarf.AttrInline)
if inline != nil {
val, ok := inline.(bool)
if ok && val {
return true
}
return !ok || val
}

abstractOrigin := entry.Val(dwarf.AttrAbstractOrigin)
Expand Down Expand Up @@ -124,12 +121,12 @@ func EntryFileReader(cu *dwarf.Entry, d *dwarf.Data) func(entry *dwarf.Entry) st
if entry.Val(dwarf.AttrTrampoline) == nil {
fileIndexAny := entry.Val(dwarf.AttrDeclFile)
if fileIndexAny == nil {
slog.Warn(fmt.Sprintf("Failed to load DWARF function file: %s", EntryPrettyPrinter(entry)))
slog.Warn(fmt.Sprintf("Failed to load DWARF function file: %s", EntryPrettyPrint(entry)))
return defaultName
}
fileIndex, ok := fileIndexAny.(int64)
if !ok || fileIndex < 0 || int(fileIndex) >= len(files) {
slog.Warn(fmt.Sprintf("Failed to load DWARF function file: %s", EntryPrettyPrinter(entry)))
slog.Warn(fmt.Sprintf("Failed to load DWARF function file: %s", EntryPrettyPrint(entry)))
return defaultName
}

Expand All @@ -140,10 +137,14 @@ func EntryFileReader(cu *dwarf.Entry, d *dwarf.Data) func(entry *dwarf.Entry) st
}
}

func EntryPrettyPrinter(entry *dwarf.Entry) string {
func EntryPrettyPrint(entry *dwarf.Entry) string {
ret := new(strings.Builder)
ret.WriteString(entry.Tag.String())
ret.WriteString(" ")
ret.WriteString(strconv.Itoa(int(entry.Offset)))
ret.WriteString(" ")
for _, field := range entry.Field {
ret.WriteString(fmt.Sprintf("%#v", field))
ret.WriteString(fmt.Sprintf("%#v ", field))
}

return ret.String()
Expand Down
17 changes: 12 additions & 5 deletions internal/entity/addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,30 @@ func (a *AddrPos) String() string {
type Addr struct {
*AddrPos

Pkg *Package // package can be nil for cgo symbols
Pkg *Package // package can be nil for cgo symbols

Function *Function // for symbol source it will be a nil
Symbol *Symbol // for function source it will be a nil

SourceType AddrSourceType

Meta any
}

func (a *Addr) String() string {
var pkgName, funcName string
ret := new(strings.Builder)
_, _ = fmt.Fprintf(ret, "AddrPos: %s", a.AddrPos)
if a.Pkg != nil {
pkgName = a.Pkg.Name
_, _ = fmt.Fprintf(ret, " Pkg: %s", a.Pkg.Name)
}
if a.Function != nil {
funcName = a.Function.Name
_, _ = fmt.Fprintf(ret, " Function: %s", a.Function.Name)
}
if a.Symbol != nil {
_, _ = fmt.Fprintf(ret, " Symbol: %s", a.Symbol.Name)
}
return fmt.Sprintf("AddrPos: %s Pkg: %s Function: %s SourceType: %s", a.AddrPos, pkgName, funcName, a.SourceType)
_, _ = fmt.Fprintf(ret, " SourceType: %s", a.SourceType)
return ret.String()
}

// AddrCoverage is a list of AddrPos, describe the coverage of the address space
Expand Down
6 changes: 3 additions & 3 deletions internal/entity/addr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func TestCoveragePartStringWithMultipleAddrs(t *testing.T) {
}

expected := "Pos: Addr: 1000 CodeSize: 100 Type: data\n" +
"AddrPos: Addr: 1000 CodeSize: 100 Type: data Pkg: Function: SourceType: disasm\n" +
"AddrPos: Addr: 1000 CodeSize: 100 Type: data SourceType: disasm\n" +
"AddrPos: Addr: 1000 CodeSize: 100 Type: data Pkg: main Function: main SourceType: symbol"
result := coveragePart.String()

Expand Down Expand Up @@ -178,7 +178,7 @@ func TestErrorReturnsExpectedErrorMessage(t *testing.T) {
}

expected := "addr 1000 pos Pos: Addr: 1000 CodeSize: 100 Type: data\n" +
"AddrPos: <nil> Pkg: Function: SourceType: and Pos: Addr: 10ff CodeSize: 100 Type: data\n" +
"AddrPos: <nil> Pkg: Function: SourceType: conflict"
"AddrPos: <nil> SourceType: and Pos: Addr: 10ff CodeSize: 100 Type: data\n" +
"AddrPos: <nil> SourceType: conflict"
assert.Equal(t, expected, err.Error())
}
28 changes: 15 additions & 13 deletions internal/entity/knownaddr.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import (
)

type KnownAddr struct {
Text AddrSpace
TextAddrSpace AddrSpace

Symbol AddrSpace
SymbolCoverage AddrCoverage
SymbolAddrSpace AddrSpace
SymbolCoverage AddrCoverage
}

func NewKnownAddr() *KnownAddr {
return &KnownAddr{
Text: make(map[uint64]*Addr),
Symbol: make(map[uint64]*Addr),
SymbolCoverage: make(AddrCoverage, 0),
TextAddrSpace: make(map[uint64]*Addr),
SymbolAddrSpace: make(map[uint64]*Addr),
SymbolCoverage: make(AddrCoverage, 0),
}
}

Expand All @@ -33,7 +33,7 @@ func (f *KnownAddr) InsertTextFromPclnTab(entry uint64, size uint64, fn *Functio

Meta: meta,
}
f.Text.Insert(&cur)
f.TextAddrSpace.Insert(&cur)
}

func (f *KnownAddr) InsertTextFromDWARF(entry uint64, size uint64, fn *Function, meta DwarfMeta) {
Expand All @@ -49,7 +49,7 @@ func (f *KnownAddr) InsertTextFromDWARF(entry uint64, size uint64, fn *Function,

Meta: meta,
}
f.Text.Insert(&cur)
f.TextAddrSpace.Insert(&cur)
}

func (f *KnownAddr) InsertSymbol(entry uint64, size uint64, p *Package, typ AddrType, meta SymbolMeta) *Addr {
Expand All @@ -60,12 +60,13 @@ func (f *KnownAddr) InsertSymbol(entry uint64, size uint64, p *Package, typ Addr
Type: typ,
},
Pkg: p,
Function: nil, // TODO: try to find the function?
Function: nil,
Symbol: NewSymbol(meta.SymbolName, entry, size, typ),
SourceType: AddrSourceSymbol,

Meta: meta,
}
f.Symbol.Insert(cur)
f.SymbolAddrSpace.Insert(cur)
return cur
}

Expand All @@ -77,17 +78,18 @@ func (f *KnownAddr) InsertSymbolFromDWARF(entry uint64, size uint64, p *Package,
Type: typ,
},
Pkg: p,
Function: nil, // TODO: try to find the function?
Function: nil,
Symbol: NewSymbol(meta.SymbolName, entry, size, typ),
SourceType: AddrSourceDwarf,

Meta: meta,
}
f.Symbol.Insert(cur)
f.SymbolAddrSpace.Insert(cur)
return cur
}

func (f *KnownAddr) BuildSymbolCoverage() {
f.SymbolCoverage = f.Symbol.ToDirtyCoverage()
f.SymbolCoverage = f.SymbolAddrSpace.ToDirtyCoverage()
}

func (f *KnownAddr) SymbolCovHas(entry uint64, size uint64) (AddrType, bool) {
Expand Down
4 changes: 2 additions & 2 deletions internal/knowninfo/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

func (k *KnownInfo) CollectCoverage() error {
// load coverage for pclntab and symbol
pclntabCov := k.KnownAddr.Text.ToDirtyCoverage()
pclntabCov := k.KnownAddr.TextAddrSpace.ToDirtyCoverage()

// merge all
covs := make([]entity.AddrCoverage, 0)
Expand All @@ -34,7 +34,7 @@ func (k *KnownInfo) CalculateSectionSize() error {
for _, cp := range k.Coverage {
s := k.Sects.FindSection(cp.Pos.Addr, cp.Pos.Size)
if s == nil {
slog.Debug(fmt.Sprintf("section not found for coverage part %s", cp))
slog.Debug(fmt.Sprintf("possible bss addr %s", cp))
continue
}
t[s] += cp.Pos.Size
Expand Down
30 changes: 21 additions & 9 deletions internal/knowninfo/dwarf.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package knowninfo

import (
"context"
"debug/dwarf"
"errors"
"fmt"
"log/slog"
"math"
Expand All @@ -18,18 +20,28 @@ import (
func (k *KnownInfo) AddDwarfVariable(entry *dwarf.Entry, d *dwarf.Data, pkg *entity.Package, ptrSize int) {
instsAny := entry.Val(dwarf.AttrLocation)
if instsAny == nil {
slog.Warn(fmt.Sprintf("no location attribute for %s", dwarfutil.EntryPrettyPrinter(entry)))
slog.Warn(fmt.Sprintf("no location attribute for %s", dwarfutil.EntryPrettyPrint(entry)))
return
}
insts, ok := instsAny.([]byte)
if !ok {
slog.Warn(fmt.Sprintf("location attribute is not []byte for %s", dwarfutil.EntryPrettyPrinter(entry)))
slog.Warn(fmt.Sprintf("location attribute is not []byte for %s", dwarfutil.EntryPrettyPrint(entry)))
return
}

addr, _, err := op.ExecuteStackProgram(op.DwarfRegisters{StaticBase: k.Wrapper.ImageBase()}, insts, ptrSize, nil)
if err != nil {
slog.Warn(fmt.Sprintf("Failed to execute location attribute for %s: %v", dwarfutil.EntryPrettyPrinter(entry), err))
level := slog.LevelDebug
if !errors.Is(err, op.ErrMemoryReadUnavailable) {
level = slog.LevelWarn
}
slog.Log(context.Background(),
level,
fmt.Sprintf(
"Failed to execute location attribute for %s: %v",
dwarfutil.EntryPrettyPrint(entry), err,
),
)
return
}

Expand All @@ -41,7 +53,7 @@ func (k *KnownInfo) AddDwarfVariable(entry *dwarf.Entry, d *dwarf.Data, pkg *ent
return k.Wrapper.ReadAddr(addrCb, size)
})
if err != nil {
slog.Warn(fmt.Sprintf("Failed to load DWARF var %s: %v", dwarfutil.EntryPrettyPrinter(entry), err))
slog.Warn(fmt.Sprintf("Failed to load DWARF var %s: %v", dwarfutil.EntryPrettyPrint(entry), err))
return
}

Expand Down Expand Up @@ -86,7 +98,7 @@ func (k *KnownInfo) AddDwarfSubProgram(
) {
subEntryName, ok := subEntry.Val(dwarf.AttrName).(string)
if !ok {
slog.Warn(fmt.Sprintf("Failed to load DWARF function name: %s", dwarfutil.EntryPrettyPrinter(subEntry)))
slog.Warn(fmt.Sprintf("Failed to load DWARF function name: %s", dwarfutil.EntryPrettyPrint(subEntry)))
return
}

Expand Down Expand Up @@ -129,7 +141,7 @@ func (k *KnownInfo) AddDwarfSubProgram(
added := pkg.AddFuncIfNotExists(filename, fn)

if added {
k.KnownAddr.Text.Insert(&entity.Addr{
k.KnownAddr.TextAddrSpace.Insert(&entity.Addr{
AddrPos: &entity.AddrPos{Addr: addr, Size: size, Type: entity.AddrTypeText},
Pkg: pkg,
Function: fn,
Expand All @@ -142,12 +154,12 @@ func (k *KnownInfo) AddDwarfSubProgram(
func (k *KnownInfo) GetPackageFromDwarfCompileUnit(cuEntry *dwarf.Entry) *entity.Package {
cuLang, ok := cuEntry.Val(dwarf.AttrLanguage).(int64)
if !ok {
slog.Warn(fmt.Sprintf("Failed to load DWARF compile unit language: %s", dwarfutil.EntryPrettyPrinter(cuEntry)))
slog.Warn(fmt.Sprintf("Failed to load DWARF compile unit language: %s", dwarfutil.EntryPrettyPrint(cuEntry)))
return nil
}
cuName, ok := cuEntry.Val(dwarf.AttrName).(string)
if !ok {
slog.Warn(fmt.Sprintf("Failed to load DWARF compile unit name: %s", dwarfutil.EntryPrettyPrinter(cuEntry)))
slog.Warn(fmt.Sprintf("Failed to load DWARF compile unit name: %s", dwarfutil.EntryPrettyPrint(cuEntry)))
return nil
}

Expand Down Expand Up @@ -185,7 +197,7 @@ func (k *KnownInfo) GetPackageFromDwarfCompileUnit(cuEntry *dwarf.Entry) *entity
func (k *KnownInfo) LoadDwarfCompileUnit(d *dwarf.Data, cuEntry *dwarf.Entry, pendingEntry []*dwarf.Entry, ptrSize int) {
cuLang, ok := cuEntry.Val(dwarf.AttrLanguage).(int64)
if !ok {
slog.Warn(fmt.Sprintf("Failed to load DWARF compile unit language: %s", dwarfutil.EntryPrettyPrinter(cuEntry)))
slog.Warn(fmt.Sprintf("Failed to load DWARF compile unit language: %s", dwarfutil.EntryPrettyPrint(cuEntry)))
return
}

Expand Down
Loading

0 comments on commit a33a752

Please sign in to comment.