Add libpack command for linux

This commit is contained in:
世界 2022-05-04 14:48:56 +08:00
parent d42354ab19
commit aa98ba9a24
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
4 changed files with 354 additions and 17 deletions

281
cli/libpack/main_linux.go Normal file
View file

@ -0,0 +1,281 @@
package main
import (
"archive/tar"
_ "embed"
"encoding/hex"
"io"
"io/fs"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"github.com/klauspost/compress/zstd"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sirupsen/logrus"
"github.com/u-root/u-root/pkg/ldd"
)
func main() {
err := run0()
if err != nil {
logrus.Fatal(err)
}
}
func run0() error {
os.Setenv("LD_LIBRARY_PATH", os.ExpandEnv("$LD_LIBRARY_PATH:/usr/local/lib:$PWD"))
if len(os.Args) == 1 {
logrus.Fatal("missing executable path")
}
realPath, err := filepath.Abs(os.Args[1])
if err != nil {
return E.Cause(err, os.Args[1], " not found")
}
if len(os.Args) == 2 {
os.Args = append(os.Args, realPath)
}
realName := filepath.Base(realPath)
output := os.Args[2]
output, err = filepath.Abs(output)
if err != nil {
return err
}
cachePath, err := os.MkdirTemp("", "libpack")
if err != nil {
return err
}
defer os.RemoveAll(cachePath)
contentFile, err := os.Create(cachePath + "/content")
if err != nil {
return err
}
writer, err := zstd.NewWriter(contentFile, zstd.WithEncoderLevel(zstd.SpeedBestCompression))
if err != nil {
return err
}
var ldName string
tarWriter := tar.NewWriter(writer)
libs, err := ldd.Ldd([]string{realPath})
if err != nil {
return err
}
libs = common.Filter(libs, func(it *ldd.FileInfo) bool {
if strings.HasPrefix(it.Name(), "ld-") {
ldName = it.Name()
return false
}
/*if strings.HasPrefix(it.FullName, "/usr/lib") {
logrus.Info("skipped ", it.FullName)
return false
}*/
return true
})
if ldName == "" {
for _, lib := range libs {
logrus.Info(lib.FullName)
}
logrus.Fatal("not a dynamically linked executable i thk")
}
sort.Slice(libs, func(i, j int) bool {
lName := filepath.Base(libs[i].FullName)
rName := filepath.Base(libs[j].FullName)
if lName == realName {
return false
} else if rName == realName {
return true
}
return lName > rName
})
for _, lib := range libs {
libName := filepath.Base(lib.FullName)
var linkName string
if lib.FileInfo.Mode()&fs.ModeSymlink != 0 {
linkName, err = os.Readlink(lib.FullName)
if err != nil {
return err
}
linkName = filepath.Base(libName)
if libName == linkName {
continue
}
logrus.Info(">> ", libName, " => ", linkName)
} else {
logrus.Info(">> ", libName)
}
header, err := tar.FileInfoHeader(lib.FileInfo, linkName)
if err != nil {
return err
}
header.Name = libName
err = tarWriter.WriteHeader(header)
if err != nil {
return err
}
libFile, err := os.Open(lib.FullName)
if err != nil {
return err
}
_, err = io.CopyN(tarWriter, libFile, header.Size)
libFile.Close()
if err != nil {
return err
}
}
err = tarWriter.Close()
if err != nil {
return err
}
err = writer.Close()
if err != nil {
return err
}
err = contentFile.Close()
if err != nil {
return err
}
hash, err := common.SHA224File(cachePath + "/content")
if err != nil {
return err
}
err = common.WriteFile(cachePath+"/main.go", []byte(`package main
import (
"archive/tar"
"bytes"
_ "embed"
"io"
"log"
"os"
"syscall"
"github.com/klauspost/compress/zstd"
"github.com/sagernet/sing/common"
)
//go:embed content
var content []byte
const (
execName = "`+realName+`"
hash = "`+hex.EncodeToString(hash)+`"
)
var (
basePath = os.TempDir() + "/.sing/" + execName
dirPath = basePath + "/" + hash
execPath = dirPath + "/" + execName
)
func main() {
log.SetFlags(0)
err := os.Setenv("LD_LIBRARY_PATH", dirPath)
if err != nil {
log.Fatalln(err)
}
err = main0()
if err != nil {
log.Fatalln(err)
}
}
//noinspection GoBoolExpressions
func main0() error {
if !common.FileExists(dirPath + "/" + hash) {
os.RemoveAll(basePath)
}
if common.FileExists(execPath) {
return syscall.Exec(execPath, os.Args, os.Environ())
}
os.RemoveAll(basePath)
os.MkdirAll(dirPath, 0o755)
reader, err := zstd.NewReader(bytes.NewReader(content))
if err != nil {
return err
}
tarReader := tar.NewReader(reader)
for {
header, err := tarReader.Next()
if err != nil {
if err == io.EOF {
break
}
return err
}
if header.FileInfo().IsDir() {
os.MkdirAll(dirPath+"/"+header.Name, 0o755)
continue
}
libFile, err := os.OpenFile(dirPath+"/"+header.Name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o755)
if err != nil {
return err
}
_, err = io.CopyN(libFile, tarReader, header.Size)
if err != nil {
return err
}
libFile.Close()
}
reader.Close()
return syscall.Exec(execPath, os.Args, os.Environ())
}`))
if err != nil {
return err
}
err = common.WriteFile(cachePath+"/go.mod", []byte(`module output
go 1.18
require (
github.com/klauspost/compress latest
github.com/sagernet/sing latest
)`))
if err != nil {
return err
}
err = runAs(cachePath, "go", "mod", "tidy")
if err != nil {
return err
}
err = runAs(cachePath, "go", "build", "-o", output, "-trimpath", "-ldflags", "-s -w -buildid=", ".")
if err != nil {
return err
}
return nil
}
func runAs(dir string, name string, args ...string) error {
var argc []string
for _, arg := range args {
if strings.Contains(arg, " ") {
argc = append(argc, "\"", arg, "\"")
} else {
argc = append(argc, arg)
}
}
logrus.Info(">> ", name, " ", strings.Join(argc, " "))
command := exec.Command(name, args...)
command.Dir = dir
command.Stdout = os.Stdout
command.Stderr = os.Stderr
command.Env = os.Environ()
command.Env = append(command.Env, "CGO_ENABLED=0")
return command.Run()
}

50
common/hash.go Normal file
View file

@ -0,0 +1,50 @@
package common
import (
"crypto/sha256"
"crypto/sha512"
"io"
"os"
)
func SHA224File(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
hash := sha256.New224()
_, err = io.Copy(hash, file)
if err != nil {
return nil, err
}
return hash.Sum(nil), nil
}
func SHA256File(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
hash := sha256.New()
_, err = io.Copy(hash, file)
if err != nil {
return nil, err
}
return hash.Sum(nil), nil
}
func SHA512File(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
hash := sha512.New()
_, err = io.Copy(hash, file)
if err != nil {
return nil, err
}
return hash.Sum(nil), nil
}

12
go.mod
View file

@ -6,19 +6,21 @@ require (
github.com/cloudflare/cloudflare-go v0.38.0
github.com/go-acme/lego/v4 v4.6.0
github.com/go-resty/resty/v2 v2.7.0
github.com/klauspost/compress v1.15.2
github.com/openacid/low v0.1.21
github.com/oschwald/geoip2-golang v1.7.0
github.com/refraction-networking/utls v1.1.0
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.4.0
github.com/u-root/u-root v0.8.1-0.20220504042106-94cc250573fb
github.com/ulikunitz/xz v0.5.10
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
github.com/v2fly/v2ray-core/v5 v5.0.5
github.com/vishvananda/netlink v1.1.0
github.com/v2fly/v2ray-core/v5 v5.0.6
github.com/vishvananda/netlink v1.2.0-beta
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d
google.golang.org/protobuf v1.28.0
lukechampine.com/blake3 v1.1.7
@ -38,10 +40,10 @@ require (
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
golang.org/x/tools v0.1.9 // indirect
golang.org/x/tools v0.1.11-0.20220325154526-54af36eca237 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
)

28
go.sum
View file

@ -232,6 +232,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.15.2 h1:3WH+AG7s2+T8o3nrM/8u2rdqUEcQhmga7smjrT41nAw=
github.com/klauspost/compress v1.15.2/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
@ -413,6 +415,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.287/go.mod
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.287/go.mod h1:CuOaLxOQr477GhMWAQPYQFUJrsZbW+ZqkAgP2uHDZXg=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/transip/gotransip/v6 v6.6.1/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
github.com/u-root/u-root v0.8.1-0.20220504042106-94cc250573fb h1:BtoOyojJgXlr/TOINOWxe+lgywETuKAalKCcPQi2up0=
github.com/u-root/u-root v0.8.1-0.20220504042106-94cc250573fb/go.mod h1:AAjVYNbjuRo6/5HRuoFEECNFjhgmRxXwTEdqLZW4IyQ=
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
@ -420,15 +424,15 @@ github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
github.com/v2fly/v2ray-core/v5 v5.0.5 h1:S9K9F1t9HMzrW3fzVYUu3cAVXArlkrkOnMresObncP0=
github.com/v2fly/v2ray-core/v5 v5.0.5/go.mod h1:Rv8eq9KRQWZt177euFJb7i2MOqrzfokVmuHGhlfo/zw=
github.com/v2fly/v2ray-core/v5 v5.0.6 h1:YTE2Ax2T6BpiDw39iGe9RrvwtID0SbQzEYY/5f3ID/I=
github.com/v2fly/v2ray-core/v5 v5.0.6/go.mod h1:Rv8eq9KRQWZt177euFJb7i2MOqrzfokVmuHGhlfo/zw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netlink v1.2.0-beta h1:CTNzkunO9iTkRaupF540+w47mexyQgNkA/ibnuKc39w=
github.com/vishvananda/netlink v1.2.0-beta/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vultr/govultr/v2 v2.7.1/go.mod h1:BvOhVe6/ZpjwcoL6/unkdQshmbS9VGbowI4QT+3DGVU=
@ -498,8 +502,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -567,7 +571,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -589,6 +592,7 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -604,8 +608,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba h1:AyHWHCBVlIYI5rgEM3o+1PLd0sLPcIAoaUckGQMaWtw=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -662,8 +666,8 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.11-0.20220325154526-54af36eca237 h1:mAhaIX1KEgotq+ju3XYdXUHvll7bzJDTgiDzIAKDdPc=
golang.org/x/tools v0.1.11-0.20220325154526-54af36eca237/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=