diff options
| author | qmuntal <quimmuntal@gmail.com> | 2023-09-04 17:30:08 +0200 |
|---|---|---|
| committer | Quim Muntal <quimmuntal@gmail.com> | 2023-10-05 08:26:52 +0000 |
| commit | bc15070085ec417d4254f8a4eda62b42de88fb37 (patch) | |
| tree | e0678a8d064fc84b978510f7ccc2f52ebb80f51b /src/cmd | |
| parent | 36ecff0893e8f30c2ff659acf8c62401f4dcebf7 (diff) | |
| download | go-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.go | 36 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/seh.go | 13 |
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: |
