github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/cmd/symbolize.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmd 16 17 import ( 18 "bufio" 19 "context" 20 "os" 21 "strconv" 22 "strings" 23 24 "github.com/google/subcommands" 25 "github.com/SagerNet/gvisor/pkg/coverage" 26 "github.com/SagerNet/gvisor/runsc/flag" 27 ) 28 29 // Symbolize implements subcommands.Command for the "symbolize" command. 30 type Symbolize struct { 31 dumpAll bool 32 } 33 34 // Name implements subcommands.Command.Name. 35 func (*Symbolize) Name() string { 36 return "symbolize" 37 } 38 39 // Synopsis implements subcommands.Command.Synopsis. 40 func (*Symbolize) Synopsis() string { 41 return "Convert synthetic instruction pointers from kcov into positions in the runsc source code. Only used when Go coverage is enabled." 42 } 43 44 // Usage implements subcommands.Command.Usage. 45 func (*Symbolize) Usage() string { 46 return `symbolize - converts synthetic instruction pointers into positions in the runsc source code. 47 48 This command takes instruction pointers from stdin and converts them into their 49 corresponding file names and line/column numbers in the runsc source code. The 50 inputs are not interpreted as actual addresses, but as synthetic values that are 51 exposed through /sys/kernel/debug/kcov. One can extract coverage information 52 from kcov and translate those values into locations in the source code by 53 running symbolize on the same runsc binary. 54 ` 55 } 56 57 // SetFlags implements subcommands.Command.SetFlags. 58 func (c *Symbolize) SetFlags(f *flag.FlagSet) { 59 f.BoolVar(&c.dumpAll, "all", false, "dump information on all coverage blocks along with their synthetic PCs") 60 } 61 62 // Execute implements subcommands.Command.Execute. 63 func (c *Symbolize) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { 64 if f.NArg() != 0 { 65 f.Usage() 66 return subcommands.ExitUsageError 67 } 68 if !coverage.Available() { 69 return Errorf("symbolize can only be used when coverage is available.") 70 } 71 coverage.InitCoverageData() 72 73 if c.dumpAll { 74 if err := coverage.WriteAllBlocks(os.Stdout); err != nil { 75 return Errorf("Failed to write out blocks: %v", err) 76 } 77 return subcommands.ExitSuccess 78 } 79 80 scanner := bufio.NewScanner(os.Stdin) 81 for scanner.Scan() { 82 // Input is always base 16, but may or may not have a leading "0x". 83 str := strings.TrimPrefix(scanner.Text(), "0x") 84 pc, err := strconv.ParseUint(str, 16 /* base */, 64 /* bitSize */) 85 if err != nil { 86 return Errorf("Failed to symbolize \"%s\": %v", scanner.Text(), err) 87 } 88 if err := coverage.Symbolize(os.Stdout, pc); err != nil { 89 return Errorf("Failed to symbolize \"%s\": %v", scanner.Text(), err) 90 } 91 } 92 return subcommands.ExitSuccess 93 }