summaryrefslogtreecommitdiffstats
path: root/src/runtime/debug/mod.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/debug/mod.go')
-rw-r--r--src/runtime/debug/mod.go114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/runtime/debug/mod.go b/src/runtime/debug/mod.go
new file mode 100644
index 0000000..0381bdc
--- /dev/null
+++ b/src/runtime/debug/mod.go
@@ -0,0 +1,114 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package debug
+
+import (
+ "strings"
+)
+
+// exported from runtime
+func modinfo() string
+
+// ReadBuildInfo returns the build information embedded
+// in the running binary. The information is available only
+// in binaries built with module support.
+func ReadBuildInfo() (info *BuildInfo, ok bool) {
+ return readBuildInfo(modinfo())
+}
+
+// BuildInfo represents the build information read from
+// the running binary.
+type BuildInfo struct {
+ Path string // The main package path
+ Main Module // The module containing the main package
+ Deps []*Module // Module dependencies
+}
+
+// Module represents a module.
+type Module struct {
+ Path string // module path
+ Version string // module version
+ Sum string // checksum
+ Replace *Module // replaced by this module
+}
+
+func readBuildInfo(data string) (*BuildInfo, bool) {
+ if len(data) < 32 {
+ return nil, false
+ }
+ data = data[16 : len(data)-16]
+
+ const (
+ pathLine = "path\t"
+ modLine = "mod\t"
+ depLine = "dep\t"
+ repLine = "=>\t"
+ )
+
+ readEntryFirstLine := func(elem []string) (Module, bool) {
+ if len(elem) != 2 && len(elem) != 3 {
+ return Module{}, false
+ }
+ sum := ""
+ if len(elem) == 3 {
+ sum = elem[2]
+ }
+ return Module{
+ Path: elem[0],
+ Version: elem[1],
+ Sum: sum,
+ }, true
+ }
+
+ var (
+ info = &BuildInfo{}
+ last *Module
+ line string
+ ok bool
+ )
+ // Reverse of cmd/go/internal/modload.PackageBuildInfo
+ for len(data) > 0 {
+ i := strings.IndexByte(data, '\n')
+ if i < 0 {
+ break
+ }
+ line, data = data[:i], data[i+1:]
+ switch {
+ case strings.HasPrefix(line, pathLine):
+ elem := line[len(pathLine):]
+ info.Path = elem
+ case strings.HasPrefix(line, modLine):
+ elem := strings.Split(line[len(modLine):], "\t")
+ last = &info.Main
+ *last, ok = readEntryFirstLine(elem)
+ if !ok {
+ return nil, false
+ }
+ case strings.HasPrefix(line, depLine):
+ elem := strings.Split(line[len(depLine):], "\t")
+ last = new(Module)
+ info.Deps = append(info.Deps, last)
+ *last, ok = readEntryFirstLine(elem)
+ if !ok {
+ return nil, false
+ }
+ case strings.HasPrefix(line, repLine):
+ elem := strings.Split(line[len(repLine):], "\t")
+ if len(elem) != 3 {
+ return nil, false
+ }
+ if last == nil {
+ return nil, false
+ }
+ last.Replace = &Module{
+ Path: elem[0],
+ Version: elem[1],
+ Sum: elem[2],
+ }
+ last = nil
+ }
+ }
+ return info, true
+}