internal/gocore: update to handle 1.12 core files Just a few adjustments to handle runtime changes. Use zip files for test data so we don't use so much disk space for large core files. See golang/go#28081. Fixes golang/go#30631 Change-Id: I6a11aae56e715540fc320cbe70e426eeafa2f64d Reviewed-on: https://go-review.googlesource.com/c/debug/+/175497 Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/internal/gocore/gocore_test.go b/internal/gocore/gocore_test.go index dac1cb1..b1567a3 100644 --- a/internal/gocore/gocore_test.go +++ b/internal/gocore/gocore_test.go
@@ -7,8 +7,15 @@ package gocore import ( + "archive/zip" "fmt" + "io" + "io/ioutil" + "os" + "path" + "path/filepath" "reflect" + "strings" "testing" "golang.org/x/debug/internal/core" @@ -36,7 +43,26 @@ if version == "1.9" { version = "" } - c, err := core.Core(fmt.Sprintf("testdata/core%s", version), "testdata", "") + var file string + var base string + if strings.HasSuffix(version, ".zip") { + // Make temporary directory. + dir, err := ioutil.TempDir("", strings.TrimSuffix(version, ".zip")+"_") + if err != nil { + t.Fatalf("can't make temp directory: %s", err) + } + defer os.RemoveAll(dir) + + // Unpack test into directory. + unzip(t, filepath.Join("testdata", version), dir) + + file = filepath.Join(dir, "tmp", "coretest", "core") + base = dir + } else { + file = fmt.Sprintf("testdata/core%s", version) + base = "testdata" + } + c, err := core.Core(file, base, "") if err != nil { t.Fatalf("can't load test core file: %s", err) } @@ -47,6 +73,40 @@ return p } +// unzip unpacks the zip file name into the directory dir. +func unzip(t *testing.T, name, dir string) { + r, err := zip.OpenReader(name) + if err != nil { + t.Fatalf("can't read zip file %s: %s", name, err) + } + for _, f := range r.File { + rf, err := f.Open() + if err != nil { + t.Fatalf("can't read entry %s: %s", f.Name, err) + } + err = os.MkdirAll(path.Dir(filepath.Join(dir, f.Name)), 0777) + if err != nil { + t.Fatalf("can't make directory: %s", err) + } + wf, err := os.Create(filepath.Join(dir, f.Name)) + if err != nil { + t.Fatalf("can't write entry %s: %s", f.Name, err) + } + _, err = io.Copy(wf, rf) + if err != nil { + t.Fatalf("can't copy %s: %s", f.Name, err) + } + err = rf.Close() + if err != nil { + t.Fatalf("can't close reader %s: %s", f.Name, err) + } + err = wf.Close() + if err != nil { + t.Fatalf("can't close writer %s: %s", f.Name, err) + } + } +} + func TestObjects(t *testing.T) { p := loadExample(t) n := 0 @@ -197,4 +257,5 @@ func TestVersions(t *testing.T) { loadExampleVersion(t, "1.10") loadExampleVersion(t, "1.11") + loadExampleVersion(t, "1.12.zip") }
diff --git a/internal/gocore/module.go b/internal/gocore/module.go index 85c3826..2f5e632 100644 --- a/internal/gocore/module.go +++ b/internal/gocore/module.go
@@ -69,7 +69,12 @@ a = a.Add(4) } a = a.Align(r.p.proc.PtrSize()) - n = r.Field("nfuncdata").Int32() + + if nfd := r.Field("nfuncdata"); nfd.typ.Size == 1 { // go 1.12 and beyond, this is a uint8 + n = int32(nfd.Uint8()) + } else { // go 1.11 and earlier, this is an int32 + n = nfd.Int32() + } for i := int32(0); i < n; i++ { f.funcdata = append(f.funcdata, r.p.proc.ReadPtr(a)) a = a.Add(r.p.proc.PtrSize())
diff --git a/internal/gocore/process.go b/internal/gocore/process.go index 05c7c84..a3fe7b1 100644 --- a/internal/gocore/process.go +++ b/internal/gocore/process.go
@@ -400,8 +400,14 @@ } case spanFree: freeSpanSize += spanSize - nReleased := int64(s.Field("npreleased").Uintptr()) - releasedSpanSize += nReleased * pageSize + if s.HasField("npreleased") { // go 1.11 and earlier + nReleased := int64(s.Field("npreleased").Uintptr()) + releasedSpanSize += nReleased * pageSize + } else { // go 1.12 and beyond + if s.Field("scavenged").Bool() { + releasedSpanSize += spanSize + } + } case spanDead: // These are just deallocated span descriptors. They use no heap. case spanManual:
diff --git a/internal/gocore/region.go b/internal/gocore/region.go index a8145d4..e4fd59a 100644 --- a/internal/gocore/region.go +++ b/internal/gocore/region.go
@@ -102,6 +102,15 @@ return r.p.proc.ReadUint8(r.a) } +// Bool returns the bool value stored in r. +// r must have type bool. +func (r region) Bool() bool { + if r.typ.Kind != KindBool { + panic("bad bool type " + r.typ.Name) + } + return r.p.proc.ReadUint8(r.a) != 0 +} + // String returns the value of the string stored in r. func (r region) String() string { if r.typ.Kind != KindString {
diff --git a/internal/gocore/testdata/1.12.zip b/internal/gocore/testdata/1.12.zip new file mode 100644 index 0000000..4d2a74a --- /dev/null +++ b/internal/gocore/testdata/1.12.zip Binary files differ
diff --git a/internal/gocore/testdata/README b/internal/gocore/testdata/README index e3922dc..af06176 100644 --- a/internal/gocore/testdata/README +++ b/internal/gocore/testdata/README
@@ -15,3 +15,18 @@ core1.10 is produced in the same way, except using go1.10.0. core1.11 is produced in the same way, except using go1.11.0. + + +steps for subsequent versions: + +mkdir /tmp/coretest +cd /tmp/coretest +rm -fr * // in case there's old junk there +cat the above program into test.go +go build test.go +ulimit -c unlimited +GOTRACEBACK=crash ./test +zip 1.12.zip /tmp/coretest/core /tmp/coretest/test // use your version number + +Then move the 1.12.zip to this directory. +Add a new test to TestVersions in ../gocore_test.go.