vulncheck/internal/binscan: add a test

Add a short test of ExtractPackagesAndSymbols.

Also, fix a bug in internal/gosym.

Change-Id: I0829975d08d4c9da0ff455afc7349df68d1f3573
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/398755
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
diff --git a/vulncheck/internal/binscan/scan.go b/vulncheck/internal/binscan/scan.go
index ec8a5ea..954d097 100644
--- a/vulncheck/internal/binscan/scan.go
+++ b/vulncheck/internal/binscan/scan.go
@@ -14,7 +14,6 @@
 
 import (
 	"debug/buildinfo"
-	"debug/gosym"
 	"errors"
 	"fmt"
 	"io"
@@ -23,6 +22,7 @@
 	"strings"
 
 	"golang.org/x/tools/go/packages"
+	"golang.org/x/vuln/vulncheck/internal/gosym"
 )
 
 func debugModulesToPackagesModules(debugModules []*debug.Module) []*packages.Module {
diff --git a/vulncheck/internal/binscan/scan_test.go b/vulncheck/internal/binscan/scan_test.go
index b87554c..c5cb210 100644
--- a/vulncheck/internal/binscan/scan_test.go
+++ b/vulncheck/internal/binscan/scan_test.go
@@ -2,6 +2,35 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build go1.18
+// +build go1.18
+
 package binscan
 
-// TODO(zpavlinovic): add tests.
+import (
+	"os"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"golang.org/x/vuln/vulncheck/internal/buildtest"
+)
+
+func TestExtractPackagesAndSymbols(t *testing.T) {
+	binary, done := buildtest.GoBuild(t, "testdata")
+	defer done()
+
+	f, err := os.Open(binary)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	_, syms, err := ExtractPackagesAndSymbols(f)
+	if err != nil {
+		t.Fatal(err)
+	}
+	got := syms["main"]
+	want := []string{"main"}
+	if !cmp.Equal(got, want) {
+		t.Errorf("\ngot  %q\nwant %q", got, want)
+	}
+}
diff --git a/vulncheck/internal/binscan/testdata/main.go b/vulncheck/internal/binscan/testdata/main.go
new file mode 100644
index 0000000..7009b8e
--- /dev/null
+++ b/vulncheck/internal/binscan/testdata/main.go
@@ -0,0 +1,13 @@
+package main
+
+func main() {
+	f()
+}
+
+func f() {
+	g()
+}
+
+func g() int {
+	return 1
+}
diff --git a/vulncheck/internal/gosym/pclntab.go b/vulncheck/internal/gosym/pclntab.go
index 9ef0f71..f0d3484 100644
--- a/vulncheck/internal/gosym/pclntab.go
+++ b/vulncheck/internal/gosym/pclntab.go
@@ -543,7 +543,7 @@
 func (f funcData) pcln() uint32        { return f.field(6) }
 func (f funcData) npcdata() uint32     { return f.field(7) }
 func (f funcData) cuOffset() uint32    { return f.field(8) }
-func (f funcData) nfuncdata() uint32   { return f.field(9) }
+func (f funcData) nfuncdata() uint32   { return uint32(f.data[f.fieldOffset(9)+3]) }
 
 func (f funcData) fieldOffset(n uint32) uint32 {
 	// In Go 1.18, the first field of _func changed
@@ -576,13 +576,12 @@
 		off = f.fieldOffset(10) + // skip fixed part of _func
 			f.npcdata()*4 + // skip pcdata
 			uint32(i)*4 // index of i'th FUNCDATA
-		return f.t.binary.Uint32(f.data[off:])
 	} else {
 		off = f.fieldOffset(10) + // skip fixed part of _func
 			f.npcdata()*4
 		off += uint32(i) * 8
-		return f.t.binary.Uint32(f.data[off:])
 	}
+	return f.t.binary.Uint32(f.data[off:])
 }
 
 func (f funcData) pcdataOffset(i uint8) uint32 {
@@ -806,4 +805,4 @@
 
 // disableRecover causes this package not to swallow panics.
 // This is useful when making changes.
-const disableRecover = false
+const disableRecover = true