delve/pkg/dwarf/line/state_machine_test.go

129 lines
2.7 KiB
Go
Raw Normal View History

package line
import (
"bytes"
"compress/gzip"
"debug/dwarf"
"debug/macho"
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
"testing"
)
func slurpGzip(path string) ([]byte, error) {
fh, err := os.Open(path)
if err != nil {
return nil, err
}
defer fh.Close()
gzin, err := gzip.NewReader(fh)
if err != nil {
return nil, err
}
defer gzin.Close()
return ioutil.ReadAll(gzin)
}
const (
newCompileUnit = "NEW COMPILE UNIT"
debugLineEnd = "END"
)
func TestGrafana(t *testing.T) {
// Compares a full execution of our state machine on the debug_line section
// of grafana to the output generated using debug/dwarf.LineReader on the
// same section.
if runtime.GOOS == "windows" {
t.Skip("filepath.Join ruins this test on windows")
}
debugBytes, err := slurpGzip("_testdata/debug.grafana.debug.gz")
if err != nil {
t.Fatal(err)
}
exe, err := macho.NewFile(bytes.NewReader(debugBytes))
if err != nil {
t.Fatal(err)
}
sec := exe.Section("__debug_line")
debugLineBytes, err := sec.Data()
if err != nil {
t.Fatal(err)
}
data, err := exe.DWARF()
if err != nil {
t.Fatal(err)
}
debugLineBuffer := bytes.NewBuffer(debugLineBytes)
rdr := data.Reader()
for {
e, err := rdr.Next()
if err != nil {
t.Fatal(err)
}
if e == nil {
break
}
rdr.SkipChildren()
if e.Tag != dwarf.TagCompileUnit {
continue
}
cuname, _ := e.Val(dwarf.AttrName).(string)
lineInfo := Parse(e.Val(dwarf.AttrCompDir).(string), debugLineBuffer, t.Logf)
sm := newStateMachine(lineInfo, lineInfo.Instructions)
lnrdr, err := data.LineReader(e)
if err != nil {
t.Fatal(err)
}
checkCompileUnit(t, cuname, lnrdr, sm)
}
}
func checkCompileUnit(t *testing.T, cuname string, lnrdr *dwarf.LineReader, sm *StateMachine) {
var lne dwarf.LineEntry
for {
if err := sm.next(); err != nil {
if err != io.EOF {
t.Fatalf("state machine next error: %v", err)
}
break
}
if !sm.valid {
continue
}
err := lnrdr.Next(&lne)
if err == io.EOF {
t.Fatalf("line reader ended before our state machine for compile unit %s", cuname)
}
if err != nil {
t.Fatal(err)
}
tgt := fmt.Sprintf("%#x %s:%d isstmt:%v prologue_end:%v epilogue_begin:%v", lne.Address, lne.File.Name, lne.Line, lne.IsStmt, lne.PrologueEnd, lne.EpilogueBegin)
out := fmt.Sprintf("%#x %s:%d isstmt:%v prologue_end:%v epilogue_begin:%v", sm.address, sm.file, sm.line, sm.isStmt, sm.prologueEnd, sm.epilogueBegin)
if out != tgt {
t.Errorf("mismatch:\n")
t.Errorf("got:\t%s\n", out)
t.Errorf("expected:\t%s\n", tgt)
t.Fatal("previous error")
}
}
err := lnrdr.Next(&lne)
if err != io.EOF {
t.Fatalf("state machine ended before the line reader for compile unit %s", cuname)
}
}