| |
| |
| |
|
|
| package loadpe |
|
|
| import ( |
| "cmd/internal/objabi" |
| "cmd/internal/sys" |
| "cmd/link/internal/loader" |
| "cmd/link/internal/sym" |
| "fmt" |
| "sort" |
| ) |
|
|
| const ( |
| UNW_FLAG_EHANDLER = 1 << 3 |
| UNW_FLAG_UHANDLER = 2 << 3 |
| UNW_FLAG_CHAININFO = 4 << 3 |
| unwStaticDataSize = 4 |
| unwCodeSize = 2 |
| ) |
|
|
| |
| |
| |
| func processSEH(ldr *loader.Loader, arch *sys.Arch, pdata sym.LoaderSym, xdata sym.LoaderSym) error { |
| switch arch.Family { |
| case sys.AMD64: |
| ldr.SetAttrReachable(pdata, true) |
| if xdata != 0 { |
| ldr.SetAttrReachable(xdata, true) |
| } |
| return processSEHAMD64(ldr, pdata) |
| default: |
| |
| return fmt.Errorf("unsupported architecture for SEH: %v", arch.Family) |
| } |
| } |
|
|
| func processSEHAMD64(ldr *loader.Loader, pdata sym.LoaderSym) error { |
| |
| |
| |
| |
| |
| |
| |
| rels := ldr.Relocs(pdata) |
| if rels.Count()%3 != 0 { |
| return fmt.Errorf(".pdata symbol %q has invalid relocation count", ldr.SymName(pdata)) |
| } |
| for i := 0; i < rels.Count(); i += 3 { |
| xrel := rels.At(i + 2) |
| handler := findHandlerInXDataAMD64(ldr, xrel.Sym(), xrel.Add()) |
| if handler != 0 { |
| sb := ldr.MakeSymbolUpdater(rels.At(i).Sym()) |
| r, _ := sb.AddRel(objabi.R_KEEP) |
| r.SetSym(handler) |
| } |
| } |
| return nil |
| } |
|
|
| |
| |
| |
| |
| func findHandlerInXDataAMD64(ldr *loader.Loader, xsym sym.LoaderSym, add int64) loader.Sym { |
| data := ldr.Data(xsym) |
| if add < 0 || add+unwStaticDataSize > int64(len(data)) { |
| return 0 |
| } |
| data = data[add:] |
| var isChained bool |
| switch flag := data[0]; { |
| case flag&UNW_FLAG_EHANDLER != 0 || flag&UNW_FLAG_UHANDLER != 0: |
| |
| case flag&UNW_FLAG_CHAININFO != 0: |
| isChained = true |
| default: |
| |
| return 0 |
| } |
| codes := data[2] |
| if codes%2 != 0 { |
| |
| codes += 1 |
| } |
| |
| |
| targetOff := add + unwStaticDataSize + unwCodeSize*int64(codes) |
| xrels := ldr.Relocs(xsym) |
| xrelsCount := xrels.Count() |
| idx := sort.Search(xrelsCount, func(i int) bool { |
| return int64(xrels.At(i).Off()) >= targetOff |
| }) |
| if idx == xrelsCount { |
| return 0 |
| } |
| if isChained { |
| |
| idx += 2 |
| if idx >= xrelsCount { |
| return 0 |
| } |
| r := xrels.At(idx) |
| return findHandlerInXDataAMD64(ldr, r.Sym(), r.Add()) |
| } |
| return xrels.At(idx).Sym() |
| } |
|
|