github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/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/MerlinKodo/gvisor/pkg/coverage" 25 "github.com/MerlinKodo/gvisor/runsc/cmd/util" 26 "github.com/MerlinKodo/gvisor/runsc/flag" 27 "github.com/google/subcommands" 28 ) 29 30 // Symbolize implements subcommands.Command for the "symbolize" command. 31 type Symbolize struct { 32 dumpAll bool 33 } 34 35 // Name implements subcommands.Command.Name. 36 func (*Symbolize) Name() string { 37 return "symbolize" 38 } 39 40 // Synopsis implements subcommands.Command.Synopsis. 41 func (*Symbolize) Synopsis() string { 42 return "Convert synthetic instruction pointers from kcov into positions in the runsc source code. Only used when Go coverage is enabled." 43 } 44 45 // Usage implements subcommands.Command.Usage. 46 func (*Symbolize) Usage() string { 47 return `symbolize - converts synthetic instruction pointers into positions in the runsc source code. 48 49 This command takes instruction pointers from stdin and converts them into their 50 corresponding file names and line/column numbers in the runsc source code. The 51 inputs are not interpreted as actual addresses, but as synthetic values that are 52 exposed through /sys/kernel/debug/kcov. One can extract coverage information 53 from kcov and translate those values into locations in the source code by 54 running symbolize on the same runsc binary. 55 ` 56 } 57 58 // SetFlags implements subcommands.Command.SetFlags. 59 func (c *Symbolize) SetFlags(f *flag.FlagSet) { 60 f.BoolVar(&c.dumpAll, "all", false, "dump information on all coverage blocks along with their synthetic PCs") 61 } 62 63 // Execute implements subcommands.Command.Execute. 64 func (c *Symbolize) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus { 65 if f.NArg() != 0 { 66 f.Usage() 67 return subcommands.ExitUsageError 68 } 69 if !coverage.Available() { 70 return util.Errorf("symbolize can only be used when coverage is available.") 71 } 72 coverage.InitCoverageData() 73 74 if c.dumpAll { 75 if err := coverage.WriteAllBlocks(os.Stdout); err != nil { 76 return util.Errorf("Failed to write out blocks: %v", err) 77 } 78 return subcommands.ExitSuccess 79 } 80 81 scanner := bufio.NewScanner(os.Stdin) 82 for scanner.Scan() { 83 // Input is always base 16, but may or may not have a leading "0x". 84 str := strings.TrimPrefix(scanner.Text(), "0x") 85 pc, err := strconv.ParseUint(str, 16 /* base */, 64 /* bitSize */) 86 if err != nil { 87 return util.Errorf("Failed to symbolize \"%s\": %v", scanner.Text(), err) 88 } 89 if err := coverage.Symbolize(os.Stdout, pc); err != nil { 90 return util.Errorf("Failed to symbolize \"%s\": %v", scanner.Text(), err) 91 } 92 } 93 return subcommands.ExitSuccess 94 }