aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorqmuntal <quimmuntal@gmail.com>2023-09-04 17:30:08 +0200
committerQuim Muntal <quimmuntal@gmail.com>2023-10-05 08:26:52 +0000
commitbc15070085ec417d4254f8a4eda62b42de88fb37 (patch)
treee0678a8d064fc84b978510f7ccc2f52ebb80f51b /src/cmd
parent36ecff0893e8f30c2ff659acf8c62401f4dcebf7 (diff)
downloadgo-bc15070085ec417d4254f8a4eda62b42de88fb37.tar.xz
runtime: support SetUnhandledExceptionFilter on Windows
The Windows unhandled exception mechanism fails to call the callback set in SetUnhandledExceptionFilter if the stack can't be correctly unwound. Some cgo glue code was not properly chaining the frame pointer, making the stack unwind to fail in case of an exception inside a cgo call. This CL fix that and adds a test case to avoid regressions. Fixes #50951 Change-Id: Ic782b5257fe90b05e3def8dbf0bb8d4ed37a190b Reviewed-on: https://go-review.googlesource.com/c/go/+/525475 Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/internal/obj/x86/seh.go36
-rw-r--r--src/cmd/link/internal/ld/seh.go13
2 files changed, 42 insertions, 7 deletions
diff --git a/src/cmd/internal/obj/x86/seh.go b/src/cmd/internal/obj/x86/seh.go
index e7d3d571b7..71cdd36642 100644
--- a/src/cmd/internal/obj/x86/seh.go
+++ b/src/cmd/internal/obj/x86/seh.go
@@ -97,17 +97,32 @@ func populateSeh(ctxt *obj.Link, s *obj.LSym) (sehsym *obj.LSym) {
// https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
const (
- UWOP_PUSH_NONVOL = 0
- UWOP_SET_FPREG = 3
- SEH_REG_BP = 5
+ UWOP_PUSH_NONVOL = 0
+ UWOP_SET_FPREG = 3
+ SEH_REG_BP = 5
+ UNW_FLAG_EHANDLER = 1 << 3
)
+ var exceptionHandler *obj.LSym
+ var flags uint8
+ if s.Name == "runtime.asmcgocall_landingpad" {
+ // Most cgo calls go through runtime.asmcgocall_landingpad,
+ // we can use it to catch exceptions from C code.
+ // TODO: use a more generic approach to identify which calls need an exception handler.
+ exceptionHandler = ctxt.Lookup("runtime.sehtramp")
+ if exceptionHandler == nil {
+ ctxt.Diag("missing runtime.sehtramp\n")
+ return
+ }
+ flags = UNW_FLAG_EHANDLER
+ }
+
// Fow now we only support operations which are encoded
// using a single 2-byte node, so the number of nodes
// is the number of operations.
nodes := uint8(2)
buf := newsehbuf(ctxt, nodes)
- buf.write8(1) // Flags + version
+ buf.write8(flags | 1) // Flags + version
buf.write8(uint8(movbp.Link.Pc)) // Size of prolog
buf.write8(nodes) // Count of nodes
buf.write8(SEH_REG_BP) // FP register
@@ -119,8 +134,10 @@ func populateSeh(ctxt *obj.Link, s *obj.LSym) (sehsym *obj.LSym) {
buf.write8(uint8(pushbp.Link.Pc))
buf.writecode(UWOP_PUSH_NONVOL, SEH_REG_BP)
- // The following 4 bytes reference the RVA of the exception handler,
- // in case the function has one. We don't use it for now.
+ // The following 4 bytes reference the RVA of the exception handler.
+ // The value is set to 0 for now, if an exception handler is needed,
+ // it will be updated later with a R_PEIMAGEOFF relocation to the
+ // exception handler.
buf.write32(0)
// The list of unwind infos in a PE binary have very low cardinality
@@ -134,6 +151,13 @@ func populateSeh(ctxt *obj.Link, s *obj.LSym) (sehsym *obj.LSym) {
s.Type = objabi.SSEHUNWINDINFO
s.Set(obj.AttrDuplicateOK, true)
s.Set(obj.AttrLocal, true)
+ if exceptionHandler != nil {
+ r := obj.Addrel(s)
+ r.Off = int32(len(buf.data) - 4)
+ r.Siz = 4
+ r.Sym = exceptionHandler
+ r.Type = objabi.R_PEIMAGEOFF
+ }
// Note: AttrContentAddressable cannot be set here,
// because the content-addressable-handling code
// does not know about aux symbols.
diff --git a/src/cmd/link/internal/ld/seh.go b/src/cmd/link/internal/ld/seh.go
index 5379528c30..43b5176a53 100644
--- a/src/cmd/link/internal/ld/seh.go
+++ b/src/cmd/link/internal/ld/seh.go
@@ -40,7 +40,7 @@ func writeSEHAMD64(ctxt *Link) {
// to deduplicate .xdata entries.
uwcache := make(map[string]int64) // aux symbol name --> .xdata offset
for _, s := range ctxt.Textp {
- if fi := ldr.FuncInfo(s); !fi.Valid() || fi.TopFrame() {
+ if fi := ldr.FuncInfo(s); !fi.Valid() {
continue
}
uw := ldr.SEHUnwindSym(s)
@@ -53,6 +53,17 @@ func writeSEHAMD64(ctxt *Link) {
off = xdata.Size()
uwcache[name] = off
xdata.AddBytes(ldr.Data(uw))
+ // The SEH unwind data can contain relocations,
+ // make sure those are copied over.
+ rels := ldr.Relocs(uw)
+ for i := 0; i < rels.Count(); i++ {
+ r := rels.At(i)
+ rel, _ := xdata.AddRel(r.Type())
+ rel.SetOff(int32(off) + r.Off())
+ rel.SetSiz(r.Siz())
+ rel.SetSym(r.Sym())
+ rel.SetAdd(r.Add())
+ }
}
// Reference: