diff mbox series

libgo patch committed: Handle function descriptors correctly

Message ID CAOyqgcU5CwH3KaTraAUGroNn898KpXua7Pik-aafuB7fa1ZoXw@mail.gmail.com
State New
Headers show
Series libgo patch committed: Handle function descriptors correctly | expand

Commit Message

Ian Lance Taylor Feb. 27, 2019, 10:35 p.m. UTC
This patch changes libgo to handle function descriptors correctly.
When using PPC64 ELF ABI v1 a function address is not a PC, but is the
address of a function descriptor.  The first field in the function
descriptor is the actual PC (see
http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-DES).
The libbacktrace library knows about this, and libgo uses actual PC
values consistently except for the helper function funcPC that appears
in both runtime and runtime/pprof.

This patch fixes funcPC by recording, in the internal/cpu package,
whether function descriptors are being used.  We have to check for
function descriptors using a C compiler check, because GCC can be
configured using --with-abi to select the ELF ABI to use.

This fixes GCC PR 89172.

Bootstrapped and ran Go tests on x86_64-pc-linux-gnu and
ppc64-linux-gnu.  Committed to mainline.

Ian
diff mbox series

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 269258)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-c9581de3804f94c5a74ce14befce5c57368722b9
+74533ed435a1a77e6f9ec8f6cf5db1695c2568e8
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 269196)
+++ libgo/Makefile.am	(working copy)
@@ -539,6 +539,7 @@  s-cpu: Makefile
 	rm -f cpugen.go.tmp
 	echo "package cpu" > cpugen.go.tmp
 	echo "const CacheLinePadSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> cpugen.go.tmp
+	echo "const FunctionDescriptors = $(FUNCTION_DESCRIPTORS)" >> cpugen.go.tmp
 	$(SHELL) $(srcdir)/mvifdiff.sh cpugen.go.tmp cpugen.go
 	$(STAMP) $@
 
Index: libgo/configure.ac
===================================================================
--- libgo/configure.ac	(revision 269196)
+++ libgo/configure.ac	(working copy)
@@ -353,6 +353,20 @@  AC_SUBST(GOARCH)
 AC_SUBST(ALLGOARCH)
 AC_SUBST(ALLGOARCHFAMILY)
 
+FUNCTION_DESCRIPTORS=false
+case ${host} in
+  rs6000*-*-* | powerpc*-*-*)
+    AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+#if _CALL_ELF == 1
+#error descriptors
+#endif
+])],
+	[FUNCTION_DESCRIPTORS=false],
+	[FUNCTION_DESCRIPTORS=true])
+    ;;
+esac
+AC_SUBST(FUNCTION_DESCRIPTORS)
+
 dnl Some files are only present when needed for specific architectures.
 GO_LIBCALL_OS_FILE=
 GO_LIBCALL_OS_ARCH_FILE=
Index: libgo/go/runtime/pprof/proto.go
===================================================================
--- libgo/go/runtime/pprof/proto.go	(revision 269196)
+++ libgo/go/runtime/pprof/proto.go	(working copy)
@@ -8,6 +8,7 @@  import (
 	"bytes"
 	"compress/gzip"
 	"fmt"
+	internalcpu "internal/cpu"
 	"io"
 	"io/ioutil"
 	"runtime"
@@ -28,7 +29,14 @@  func funcPC(f interface{}) uintptr {
 		data unsafe.Pointer
 	}
 	i := (*iface)(unsafe.Pointer(&f))
-	return **(**uintptr)(i.data)
+	r := **(**uintptr)(i.data)
+	if internalcpu.FunctionDescriptors {
+		// With PPC64 ELF ABI v1 function descriptors the
+		// function address is a pointer to a struct whose
+		// first field is the actual PC.
+		r = *(*uintptr)(unsafe.Pointer(r))
+	}
+	return r
 }
 
 // A profileBuilder writes a profile incrementally from a
Index: libgo/go/runtime/proc.go
===================================================================
--- libgo/go/runtime/proc.go	(revision 269196)
+++ libgo/go/runtime/proc.go	(working copy)
@@ -446,7 +446,14 @@  func releaseSudog(s *sudog) {
 //go:nosplit
 func funcPC(f interface{}) uintptr {
 	i := (*iface)(unsafe.Pointer(&f))
-	return **(**uintptr)(i.data)
+	r := **(**uintptr)(i.data)
+	if cpu.FunctionDescriptors {
+		// With PPC64 ELF ABI v1 function descriptors the
+		// function address is a pointer to a struct whose
+		// first field is the actual PC.
+		r = *(*uintptr)(unsafe.Pointer(r))
+	}
+	return r
 }
 
 func lockedOSThread() bool {