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.