| // Copyright 2021 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package abi_test |
| |
| import ( |
| "internal/abi" |
| "internal/testenv" |
| "os/exec" |
| "path/filepath" |
| "strings" |
| "testing" |
| ) |
| |
| func TestFuncPC(t *testing.T) { |
| // Test that FuncPC* can get correct function PC. |
| pcFromAsm := abi.FuncPCTestFnAddr |
| |
| // Test FuncPC for locally defined function |
| pcFromGo := abi.FuncPCTest() |
| if pcFromGo != pcFromAsm { |
| t.Errorf("FuncPC returns wrong PC, want %x, got %x", pcFromAsm, pcFromGo) |
| } |
| |
| // Test FuncPC for imported function |
| pcFromGo = abi.FuncPCABI0(abi.FuncPCTestFn) |
| if pcFromGo != pcFromAsm { |
| t.Errorf("FuncPC returns wrong PC, want %x, got %x", pcFromAsm, pcFromGo) |
| } |
| } |
| |
| func TestFuncPCCompileError(t *testing.T) { |
| // Test that FuncPC* on a function of a mismatched ABI is rejected. |
| testenv.MustHaveGoBuild(t) |
| |
| // We want to test internal package, which we cannot normally import. |
| // Run the assembler and compiler manually. |
| tmpdir := t.TempDir() |
| asmSrc := filepath.Join("testdata", "x.s") |
| goSrc := filepath.Join("testdata", "x.go") |
| symabi := filepath.Join(tmpdir, "symabi") |
| obj := filepath.Join(tmpdir, "x.o") |
| |
| // parse assembly code for symabi. |
| cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-gensymabis", "-o", symabi, asmSrc) |
| out, err := cmd.CombinedOutput() |
| if err != nil { |
| t.Fatalf("go tool asm -gensymabis failed: %v\n%s", err, out) |
| } |
| |
| // compile go code. |
| cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-symabis", symabi, "-o", obj, goSrc) |
| out, err = cmd.CombinedOutput() |
| if err == nil { |
| t.Fatalf("go tool compile did not fail") |
| } |
| |
| // Expect errors in line 17, 18, 20, no errors on other lines. |
| want := []string{"x.go:17", "x.go:18", "x.go:20"} |
| got := strings.Split(string(out), "\n") |
| if got[len(got)-1] == "" { |
| got = got[:len(got)-1] // remove last empty line |
| } |
| for i, s := range got { |
| if !strings.Contains(s, want[i]) { |
| t.Errorf("did not error on line %s", want[i]) |
| } |
| } |
| if len(got) != len(want) { |
| t.Errorf("unexpected number of errors, want %d, got %d", len(want), len(got)) |
| } |
| if t.Failed() { |
| t.Logf("output:\n%s", string(out)) |
| } |
| } |