package main
-// // No C code required.
+//#include <errno.h>
+//#include <string.h>
import "C"
-import "common"
+// #include
+// void cfunc() {} // uses cgo_topofstack
+
+import (
+ "common"
+ "strings"
+)
func init() {
+ _ = strings.NewReplacer() // trigger stack unwind, Issue #18190.
+ C.strerror(C.EIO) // uses cgo_topofstack
common.X = 2
}
if Buildmode == BuildmodePlugin && strings.HasPrefix(s.Extname, *flagPluginPath) {
return true
}
- return s.Type != obj.STEXT
+ if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") {
+ // reduce runtime typemap pressure, but do not
+ // export alg functions (type..*), as these
+ // appear in pclntable.
+ return true
+ }
+ if strings.HasPrefix(s.Name, "go.link.pkghash") {
+ return true
+ }
+ return s.Type >= obj.SELFSECT // only writable sections
}
func machosymtab(ctxt *Link) {
// In normal buildmodes, only add _ to C symbols, as
// Go symbols have dot in the name.
- if !strings.Contains(s.Extname, ".") || export {
+ //
+ // Do not export C symbols in plugins, as runtime C
+ // symbols like crosscall2 are in pclntab and end up
+ // pointing at the host binary, breaking unwinding.
+ // See Issue #18190.
+ cexport := !strings.Contains(s.Extname, ".") && (Buildmode != BuildmodePlugin || onlycsymbol(s))
+ if cexport || export {
Adduint8(ctxt, symstr, '_')
}
*d = out
}
+// onlycsymbol reports whether this is a cgo symbol provided by the
+// runtime and only used from C code.
+func onlycsymbol(s *Symbol) bool {
+ switch s.Name {
+ case "_cgo_topofstack", "_cgo_panic", "crosscall2":
+ return true
+ }
+ return false
+}
+
func container(s *Symbol) int {
+ if s == nil {
+ return 0
+ }
+ if Buildmode == BuildmodePlugin && onlycsymbol(s) {
+ return 1
+ }
// We want to generate func table entries only for the "lowest level" symbols,
// not containers of subsymbols.
- if s != nil && s.Type&obj.SCONTAINER != 0 {
+ if s.Type&obj.SCONTAINER != 0 {
return 1
}
return 0
modulesinit()
typelinksinit()
+ pluginftabverify(md)
+ moduledataverify1(md)
+
lock(&ifaceLock)
for _, i := range md.itablinks {
additab(i, true, false)
return md.pluginpath, syms, ""
}
+func pluginftabverify(md *moduledata) {
+ badtable := false
+ for i := 0; i < len(md.ftab); i++ {
+ entry := md.ftab[i].entry
+ if md.minpc <= entry && entry <= md.maxpc {
+ continue
+ }
+
+ f := (*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff]))
+ name := funcname(f)
+
+ // A common bug is f.entry has a relocation to a duplicate
+ // function symbol, meaning if we search for its PC we get
+ // a valid entry with a name that is useful for debugging.
+ name2 := "none"
+ entry2 := uintptr(0)
+ f2 := findfunc(entry)
+ if f2 != nil {
+ name2 = funcname(f2)
+ entry2 = f2.entry
+ }
+ badtable = true
+ println("ftab entry outside pc range: ", hex(entry), "/", hex(entry2), ": ", name, "/", name2)
+ }
+ if badtable {
+ throw("runtime: plugin has bad symbol table")
+ }
+}
+
// inRange reports whether v0 or v1 are in the range [r0, r1].
func inRange(r0, r1, v0, v1 uintptr) bool {
return (v0 >= r0 && v0 <= r1) || (v1 >= r0 && v1 <= r1)