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  }